gpt4 book ai didi

java - 通知传输控件似乎没有执行任何操作

转载 作者:行者123 更新时间:2023-12-02 10:39:39 24 4
gpt4 key购买 nike

我创建了一个可以使用 MediaBrowserServiceCompat 和 MediaSessionCompat 播放音频的应用程序。根据 android 开发人员网站上的说明,我在 MediaSessionCompat.Callback().onPlay() 方法中创建了一个通知,该方法使用 MediaStyle 提供传输控件,当提供适当的 token 时,这些控件应该连接到我的媒体 session 。即使应用程序关闭并再次打开,用于播放和暂停的应用程序内控件也会按预期工作。该服务似乎正在按预期运行。

然而,问题是,尽管通知按预期显示,但包含的暂停按钮似乎无法执行任何操作。尽管 Android 开发人员示例表明应该存在取消按钮,但事实并非如此。此外,该示例还表明,应该通过将通知滑开来停止该服务,但事实并非如此。

可以这么说,以下代码 fragment 中的任何内容都无法正常工作。只不过通知实际上确实出现了。

private NotificationCompat.Builder getMediaNotificationBuilder() {

Intent contentIntent = new Intent(mContext, MainActivity.class);
contentIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

PendingIntent pendingContentIntent = PendingIntent.getActivity(mContext, 0, contentIntent, 0);

MediaControllerCompat controller = mMediaSession.getController();

NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, "PODCAST");

builder
.setContentTitle("PODCAST")
.setContentText("THIS IS A PLACE HOLDER.")
.setSubText("Still a place holder.")

// Enable launching the player by clicking the notification
.setContentIntent(pendingContentIntent)

// Stop the service when the notification is swiped away
.setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(mContext, PlaybackStateCompat.ACTION_STOP))

// Make the transport controls visible on the lockscreen
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)

// Add an app icon and set its accent color
// Be careful about the color
.setSmallIcon(R.drawable.ic_launcher_background)
.setColor(ContextCompat.getColor(mContext, R.color.colorPrimaryDark))

// Add a pause button
.addAction(new NotificationCompat.Action(
R.drawable.ic_pause, "Pause",
MediaButtonReceiver.buildMediaButtonPendingIntent(mContext,
PlaybackStateCompat.ACTION_PAUSE)))

// Take advantage of MediaStyle features
.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mMediaSession.getSessionToken())
.setShowActionsInCompactView(0)

// Add a cancel button
.setShowCancelButton(true)
.setCancelButtonIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(mContext,
PlaybackStateCompat.ACTION_STOP)));

return builder;
}

然后我继续将此通知传递给

startForground(1, getMediaNotificationBuilder().build())

然后启动服务。

如果有必要,我很乐意分享整个应用程序源代码。我确信我在这里错过了一些非常简单的东西。

最佳答案

正如我怀疑的那样,我错过了一些非常简单的东西。为了让我的 MediaBrowserServiceCompat 子类对我的通知控件使用react,我需要重写 Service 基类中的 onStartCommand 并将其中的 Intent 传递给我的 MediaSessionCompat 对象。完成此操作后,MediaSessionCompat.Callback 应该处理该命令,假设它已被编程为这样做。这就是我的 MediaBrowserService 类内部的代码。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(LOG_TAG, "onStartCommand(): received intent " + intent.getAction() + " with flags " + flags + " and startId " + startId);
MediaButtonReceiver.handleIntent(mMediaSession, intent);
return super.onStartCommand(intent, flags, startId);
}

添加此代码后,您也应该在 logcat 中看到该方法。以防万一有人仍然遗漏了什么,您至少会知道代码正在响应您按下的按钮。

编辑:

至于通过滑动通知来停止服务,我误解了通知和用户之间的交互。用户可以将通知滑开,但前提是媒体先暂停。标准媒体播放器应用程序的通知控件进一步支持此范例。这是有道理的,因为用户可能会在收听其他内容时意外地滑开控件。

此外,我决定包含 MediaBrowserServiceCompat 类的完整源代码,希望这些附加信息能够提供一些讨论背景

public class MediaPlaybackService extends MediaBrowserServiceCompat {
private static final String LOG_TAG = "MediaPlaybackService";
private static final String MY_MEDIA_ROOT_ID = "media_root_id";
private static final String MY_EMPTY_MEDIA_ROOT_ID = "empty_root_id";

// Volume levels: Normal and Duck
// VOLUME_DUCK is the volume we set the media player to when we lose audio focus, but are allowed to reduce the volume instead of stopping playback.
public static final float VOLUME_DUCK = 0.2f;
public static final float VOLUME_NORMAL = 1.0f;

private MediaSessionCompat mMediaSession;
private MediaPlayer mMediaPlayer;

// Current local media player state
private PlaybackStateCompat.Builder mStateBuilder;
private int mState = PlaybackStateCompat.STATE_NONE;

private final class MediaSessionCallback extends MediaSessionCompat.Callback implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, AudioManager.OnAudioFocusChangeListener{

private Context mContext;

private AudioManager mAudioManager;

// Declare the "SHIT THAT'S LOUD" intent, any broadcast receiver
// that is connected to it will trigger when the headphones come unplugged
private IntentFilter shitThatsLoudIntentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private BroadcastReceiver shitThatsLoudBroadcastReceiver = new BroadcastReceiver() {
// TODO: Put me in a separate class
@Override
public void onReceive(Context context, Intent intent) {
Log.d(LOG_TAG, "SHIT THATS LOUD! The headphones have come unplugged!");
}
};

private MediaSessionCallback(Context context) {
super();

mContext = context;
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);

initMediaPlayer();
}

private void initMediaPlayer() {
try {
mMediaPlayer = new MediaPlayer();

mMediaPlayer.setDataSource("https://www.blogtalkradio.com/kylekulinski/2018/10/15/the-kyle-kulinski-show.mp3");
mMediaPlayer.setOnPreparedListener (this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnErrorListener (this);

mMediaPlayer.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, ".initMediaPlayer(): IOException: "+e.toString());
}
}

private void mediaPlay() {
registerReceiver(shitThatsLoudBroadcastReceiver, shitThatsLoudIntentFilter);
if (mAudioManager.requestAudioFocus(getAudioFocusRequest()) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.d(LOG_TAG, "Audio focus request granted.");

mState = PlaybackStateCompat.STATE_PLAYING;

mStateBuilder.setActions(PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_STOP);
mStateBuilder.setState(mState, mMediaPlayer.getCurrentPosition(), 1.0f, SystemClock.elapsedRealtime());

mMediaSession.setPlaybackState(mStateBuilder.build());
mMediaSession.setActive(true);

mMediaPlayer.start();

startService(new Intent(mContext, MediaPlaybackService.class));
startForeground(1, getMediaNotificationBuilder().build());
}
}

private void mediaPause() {

unregisterReceiver(shitThatsLoudBroadcastReceiver);

mState = PlaybackStateCompat.STATE_PAUSED;

mStateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_STOP);
mStateBuilder.setState(mState, mMediaPlayer.getCurrentPosition(), 1.0f, SystemClock.elapsedRealtime());

mMediaSession.setPlaybackState(mStateBuilder.build());

mMediaPlayer.pause();

stopForeground(false);

}

private void releaseResources() {

mMediaSession.setActive(false);

mAudioManager.abandonAudioFocusRequest(getAudioFocusRequest());

unregisterReceiver(shitThatsLoudBroadcastReceiver);

if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}

stopSelf();
stopForeground(true);
}

private NotificationCompat.Builder getMediaNotificationBuilder() {

Intent contentIntent = new Intent(mContext, MainActivity.class);
contentIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

PendingIntent pendingContentIntent = PendingIntent.getActivity(mContext, 0, contentIntent, 0);

MediaControllerCompat controller = mMediaSession.getController();

NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, "PODCAST");

builder
.setContentTitle("PODCAST")
.setContentText("THIS IS A PLACE HOLDER.")
.setSubText("Still a place holder.")

// Enable launching the player by clicking the notification
.setContentIntent(pendingContentIntent)

// Stop the service when the notification is swiped away
.setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(mContext, PlaybackStateCompat.ACTION_STOP))

// Make the transport controls visible on the lockscreen
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)

// Add an app icon and set its accent color
// Be careful about the color
.setSmallIcon(R.drawable.ic_launcher_background)
.setColor(ContextCompat.getColor(mContext, R.color.colorPrimaryDark))

// Add a pause button
.addAction(new NotificationCompat.Action(
R.drawable.ic_pause, "Pause",
MediaButtonReceiver.buildMediaButtonPendingIntent(mContext,
PlaybackStateCompat.ACTION_PLAY_PAUSE)))

// Take advantage of MediaStyle features
.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mMediaSession.getSessionToken())
.setShowActionsInCompactView(0)

// Add a cancel button
.setShowCancelButton(true)
.setCancelButtonIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(mContext,
PlaybackStateCompat.ACTION_STOP)));

return builder;
}

@Override
public void onPlay() {
super.onPlay();
Log.d(LOG_TAG, "I tried to play music");

mediaPlay();
}

@Override
public void onPause() {
super.onPause();
Log.d(LOG_TAG, "I Tried to pause");

mediaPause();
}

@Override
public void onStop() {
super.onStop();
releaseResources();
}

private AudioFocusRequest getAudioFocusRequest() {
// Request audio focus for playback, this registers the afChangeListener
AudioAttributes attrs = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
AudioFocusRequest audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setOnAudioFocusChangeListener(this)
.setAudioAttributes(attrs)
.build();

return audioFocusRequest;
}

@Override
public void onAudioFocusChange(int focusChange) {

switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
Log.d(LOG_TAG, "Audio focus has been restored after it was transiently arrested by and intrusive app. We can now start playing audio normally again.");
mMediaPlayer.setVolume(VOLUME_NORMAL, VOLUME_NORMAL);
mediaPlay();
break;

case AudioManager.AUDIOFOCUS_LOSS:
Log.d(LOG_TAG, "Audio focus was lost flat out. Save what we were doing so we don't forget about it later.");
mediaPause();
break;

case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
Log.d(LOG_TAG, "Audio focus was lost (Transient) but we might get it back later, still stop and save though.");
mediaPause();
break;

case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
Log.d(LOG_TAG, "Audio focus was lost but was just need to keep it down instead of stopping.");
mMediaPlayer.setVolume(VOLUME_DUCK, VOLUME_DUCK);
break;

default:
Log.d(LOG_TAG, "Ignoring unsupported audio focus change: "+focusChange);
break;

}

}

@Override
public void onPrepared(MediaPlayer mp) {
Log.d(LOG_TAG, "MediaSessionCallback.onPrepared(): MediaPlayer is prepared!");
// The media player is done preparing. That means we can start playing if we
// have audio focus.
}

@Override
public void onCompletion(MediaPlayer mp) {

}

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(LOG_TAG, "Media player error: what=" + what + ", extra=" + extra);
return false; // true indicates we handled the error
}
}

@Override
public void onCreate() {
super.onCreate();

// Create a MediaSessionCompat
mMediaSession = new MediaSessionCompat(this, LOG_TAG);
// Set the session's token so that client activities can communicate with it.
setSessionToken(mMediaSession.getSessionToken());
// MediaSessionCallback() has methods that handle callbacks from a media controller
mMediaSession.setCallback(new MediaSessionCallback(this));
// Enable callbacks from media buttons and transport controls
mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
);

// Set initial PlaybackState with ACTION_PLAY, so that media buttons start the player
mStateBuilder = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_PAUSE
);
mMediaSession.setPlaybackState(mStateBuilder.build());

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(LOG_TAG, "onStartCommand(): received intent " + intent.getAction() + " with flags " + flags + " and startId " + startId);
MediaButtonReceiver.handleIntent(mMediaSession, intent);
return super.onStartCommand(intent, flags, startId);
}

@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) {
return new BrowserRoot(MY_EMPTY_MEDIA_ROOT_ID, null);
}

@Override
public void onLoadChildren(@NonNull String parentMediaId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
// Browsing not allowed
if (TextUtils.equals(MY_EMPTY_MEDIA_ROOT_ID, parentMediaId)) {
result.sendResult(null);
return;
}

// TODO: If in the future we decide that we do want this class to handle the podcast metadata
// Then we must adapt what ever data podcastFactory produces into a List of MediaBrowserCompat.MediaItem objects
// The constructor of MediaItem requires that a MediaDescription object be passed to it.
// MediaDescription has a builder class which contains methods for setting Title, Artist, Uri, etc...

// MediaDescription.Builder mMediaDescriptionBuilder = new MediaDescription.Builder();

// mMediaDescriptionBuilder.setTitle(String);
// mMediaDescriptionBuilder.setMediaUri(String);

// MediaDescription mMediaDescription = mMediaDescriptionBuilder.build()

// MediaBrowserCompat.MediaItem mMediaItem =
// new MediaBrowserCompat.MediaItem(
// mMediaDescription,
// int flags -> FLAG_BROWSABLE and/or FLAG_PLAYABLE
// );

// add MediaItem to SomeList

// result.sendResult(SomeList);
}

关于java - 通知传输控件似乎没有执行任何操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53019975/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com