【问题标题】:onSkipToNext() and onSkipToPrevious() of MediaSessionCompat.Callback does not get triggeredMediaSessionCompat.Callback 的 onSkipToNext() 和 onSkipToPrevious() 没有被触发
【发布时间】:2018-05-25 05:17:16
【问题描述】:

我正在尝试在 Android 中实现通知播放器。我遵循this 指南来实现这一目标。但是根据我的要求,我需要在后台通知播放器中实现“跳到下一个”和“跳到上一个”。

到目前为止,MediaSessionCompact.Callback 的 onPlay() 和 onPause() 被触发。但是,在调试时,我注意到在通知播放器中按下下一个和上一个按钮时,不会触发 onSkipToNext() 和 onSkipToPrevious() 回调方法。

感谢您的意见。我在下面添加了相关代码。

BackgroundAudioService

private void showPlayingNotification() {
    NotificationCompat.Builder builder = MediaStyleHelper.from(BackgroundAudioService.this, mMediaSessionCompat);
    if (builder == null) {
        return;
    }

    builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_previous, "Previous", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)));
    builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_pause, "Pause", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_PLAY_PAUSE)));
    builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_next, "Next", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_SKIP_TO_NEXT)));

    builder.setStyle(new NotificationCompat.MediaStyle().setShowActionsInCompactView(0).setMediaSession(mMediaSessionCompat.getSessionToken()));
    builder.setSmallIcon(R.mipmap.ic_launcher);
    NotificationManagerCompat.from(BackgroundAudioService.this).notify(1, builder.build());
}

private void showPausedNotification() {
    NotificationCompat.Builder builder = MediaStyleHelper.from(this, mMediaSessionCompat);
    if (builder == null) {
        return;
    }

    builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_previous, "Previous", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)));
    builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_play, "Play", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_PLAY_PAUSE)));
    builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_next, "Next", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_SKIP_TO_NEXT)));


    builder.setStyle(new NotificationCompat.MediaStyle().setShowActionsInCompactView(0).setMediaSession(mMediaSessionCompat.getSessionToken()));
    builder.setSmallIcon(R.mipmap.ic_launcher);
    NotificationManagerCompat.from(this).notify(1, builder.build());
}

private MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() {

    @Override
    public void onPlay() {
        super.onPlay();
        if (!successfullyRetrievedAudioFocus()) {
            return;
        }

        mMediaSessionCompat.setActive(true);
        setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING);
        Log.d("MyLog", "STATE_PLAYING");
        showPlayingNotification();
        mMediaPlayer.start();
    }

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

        if (mMediaPlayer.isPlaying()) {
            mMediaPlayer.pause();
            setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED);
            Log.d("MyLog", "STATE_PAUSED");
            showPausedNotification();
        }
    }

    @Override
    public void onSkipToNext() {
        super.onSkipToNext();
        setMediaPlaybackState(PlaybackStateCompat.STATE_SKIPPING_TO_NEXT);
        Log.d("MyLog", "STATE_SKIPPING_TO_NEXT");
    }

    @Override
    public void onSkipToPrevious() {
        super.onSkipToPrevious();
        setMediaPlaybackState(PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS);
        Log.d("MyLog", "STATE_SKIPPING_TO_PREVIOUS");
    }
}

MediaStyleHelper

public static NotificationCompat.Builder from(
        Context context, MediaSessionCompat mediaSession) {
    MediaControllerCompat controller = mediaSession.getController();
    MediaMetadataCompat mediaMetadata = controller.getMetadata();
    MediaDescriptionCompat description = mediaMetadata.getDescription();

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
    builder
            .setContentTitle(description.getTitle())
            .setContentText(description.getSubtitle())
            .setSubText(description.getDescription())
            .setLargeIcon(description.getIconBitmap())
            .setContentIntent(controller.getSessionActivity())
            .setDeleteIntent(
                    MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_STOP))
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
    return builder;
}

MainActivity 的 onCreate

    mMediaBrowserCompat = new MediaBrowserCompat(this, new ComponentName(this, BackgroundAudioService.class),
            mMediaBrowserCompatConnectionCallback, getIntent().getExtras());

MainActivity

private MediaBrowserCompat.ConnectionCallback mMediaBrowserCompatConnectionCallback = new MediaBrowserCompat.ConnectionCallback() {

    @Override
    public void onConnected() {
        super.onConnected();
        try {
            mMediaControllerCompat = new MediaControllerCompat(MainActivity.this, mMediaBrowserCompat.getSessionToken());
            mMediaControllerCompat.registerCallback(mMediaControllerCompatCallback);
            setSupportMediaController(mMediaControllerCompat);
            getSupportMediaController().getTransportControls().playFromMediaId(String.valueOf(R.raw.warner_tautz_off_broadway), null);

        } catch( RemoteException e ) {

        }
    }
};

private MediaControllerCompat.Callback mMediaControllerCompatCallback = new MediaControllerCompat.Callback() {

    @Override
    public void onPlaybackStateChanged(PlaybackStateCompat state) {
        super.onPlaybackStateChanged(state);
        if( state == null ) {
            return;
        }

        switch( state.getState() ) {
            case PlaybackStateCompat.STATE_PLAYING: {
                mCurrentState = STATE_PLAYING;
                break;
            }
            case PlaybackStateCompat.STATE_PAUSED: {
                mCurrentState = STATE_PAUSED;
                break;
            }
            case PlaybackStateCompat.STATE_SKIPPING_TO_NEXT: {
                mCurrentState = STATE_SKIPPING_TO_NEXT;
                break;
            }
            case PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS: {
                mCurrentState = STATE_SKIPPING_TO_PREVIOUS;
            }
        }
    }
};

更新

似乎 onMediaButtonEvent() 在通知播放器中为下一个和上一个触发,两个按钮的动作名称为“android.intent.action.MEDIA_BUTTON”。

    @Override
    public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
        Log.d("MyLog", "executing onMediaButtonEvent: " + mediaButtonEvent.getAction());
        return super.onMediaButtonEvent(mediaButtonEvent);
    }

【问题讨论】:

    标签: java android android-mediaplayer mediacontroller android-mediasession


    【解决方案1】:

    在遵循相同的指南后遇到了这个问题。

    在 BackgroundAudioService 类中查找名为 setMediaPlaybackState(int state) 的方法。这是您定义 PlaybackStateCompat.Builder 并使用 setActions 定义会话上可用的当前功能的地方。

    除非作为支持的操作传入 ACTION_SKIP_TO_NEXT 和 ACTION_SKIP_TO_PREVIOUS,否则不会调用 OnSkipToNext 和 onSkipToPrevious。在将 setActions 更新为以下内容后,我设法让它工作......

    private void setMediaPlaybackState(int state) {
        PlaybackStateCompat.Builder playbackstateBuilder = new PlaybackStateCompat.Builder();
        switch (state) {
            case PlaybackStateCompat.STATE_PLAYING: {
                playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PAUSE
                        | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
                break;
            }
            default: {
                playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY
                        | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
                break;
            }
        }
    
        playbackstateBuilder.setState(state, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 0);
        mMediaSessionCompat.setPlaybackState(playbackstateBuilder.build());
    }
    

    如果有一种更简洁的方法可以做到这一点,那就太好了,但似乎所有操作都需要在一次点击中设置,并且不能在多个调用中拆分。

    【讨论】:

      【解决方案2】:

      如果你使用MediaSessionConnector,你可以通过PlaybackPreparer试试QueueNavigator,你可以在这里捕捉事件。

      参考我的 GitHub 源码 https://github.com/InvincibleCooler/EarthQuakePlayer2

      EarthquakePlaybackPreparer 类

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-14
        • 2017-11-22
        • 2012-06-03
        • 2019-11-07
        • 2018-09-01
        • 2018-12-03
        • 2021-04-23
        相关资源
        最近更新 更多