MediaSession架构中MediaPlayer和SeekBar之间的Android通信

问题描述

我正在开发音频流应用程序。我已经按照android描述here的方式设计了我的应用。在我的应用程序中,我有一个活动MainActivity,该活动根据所选功能加载片段。在其中一个片段中,我提供了一个ReplayPlayer,供用户浏览流音频,播放/暂停流等。我找到了this,并设计了自己的应用, StreamService控制着MediaPlayer,因此我的应用程序的MediaPlayer位于StreamService

问题是我正在尝试将SeekBar中的ReplayPlayerMediaPlayerStreamService中的媒体相关联。据我了解,MediaBrowserService无法绑定,与Service不同,因此我无法访问currentPosition中我的MediaPlayer的StreamService。因此,我一直沉迷于如何从我的MediaPlayer片段中访问此currentPosition的{​​{1}}。

由于其他音乐播放器应用程序清楚地显示了歌曲中的当前位置,所以我觉得有一种方法可以实现我目前正在努力的目标。我该怎么办?

预先感谢您的帮助。

AndroidManifest.xml

ReplayPlayer

StreamService.java

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/TransparentTheme"
    android:usesCleartextTraffic="true">
    <activity android:name=".MainActivity" android:windowSoftInputMode="stateVisible|adjustResize"/>

    <service android:name=".StreamService">
        <intent-filter>
            <action android:name="android.media.browse.MediaBrowserService" />
            <action android:name="android.intent.action.MEDIA_BUTTON" />
            <action android:name="android.media.browse.AUDIO_BECOMING_NOISY" />
        </intent-filter>
    </service>

    <receiver android:name="androidx.media.session.MediaButtonReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON" />
            <action android:name="android.media.AUDIO_BECOMING_NOISY" />
        </intent-filter>
    </receiver>

    <activity android:name=".SplashActivity" android:noHistory="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

解决方法

您可以在服务端的MediaSessionCompat中发布MediaPlayer的位置更新,然后在片段中,您将在MediaControllerCompat.Callback的onPlaybackStateChanged(PlaybackStateCompat state)方法中接收播放状态更新。 使用处理程序定期发布MediaPlayer更新。像这样:

public void onPlay() {
    if (!mMediaPlayer.isPlaying()) {
        mMediaPlayer.start();
        updateCurrentPosition();
    }
}

public void onPause() {
    super.onPause();
    if (mMediaPlayer.isPlaying()) {
        mMediaPlayer.pause();
        PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder()
                .setActions(PAUSE_ACTIONS)
                .setState(PlaybackStateCompat.STATE_PAUSED,mMediaPlayer.getCurrentPosition(),0)
                .build();
        stopPlaybackStateUpdate();
    }
}


private void updateCurrentPosition() {
    if (mMediaPlayer == null) {
        return;
    }
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            int currentPosition = mMediaPlayer.getCurrentPosition();
            PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder()
                    .setActions(PLAYING_ACTIONS)
                    .setState(PlaybackStateCompat.STATE_PLAYING,currentPosition,1)
                    .build();
            mMediaSession.setPlaybackState(playbackState);
            updateCurrentPosition();
        }
    },1000);
}

private void stopPlaybackStateUpdate() {
    if (handler != null) {
        handler.removeCallbacksAndMessages(null);
    }
}

您可以使用MediaSessionCompat.setMetadata(Metadata)设置媒体文件的总时长。

MediaMetadataCompat mediaMetadata = new MediaMetadataCompat.Builder()
            .putString(MediaMetadata.METADATA_KEY_TITLE,"XYZ"))
            .putLong(MediaMetadata.METADATA_KEY_DURATION,mMediaPlayer.getDuration())
            .build();

然后,在您的“片段/活动”中,您可以使用MediaController.Callback中收到的“位置更新”来设置MediaPlayer当前位置的进度(即Seekbar.setProgress())。另外,请使用当前播放媒体的总时长来设置Seekbar.setMax。

    private MediaControllerCompat.Callback mMediaControllerCallback =

        new MediaControllerCompat.Callback() {
            @Override
            public void onMetadataChanged(MediaMetadataCompat metadata) {
                super.onMetadataChanged(metadata);
                int totalDuration = (int) metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION);
                mSeekBar.setMax(totalDuration);
            }

            @Override
            public void onPlaybackStateChanged(PlaybackStateCompat state) {
                mSeekBar.setMax(state.getPosition()); //You will receive MediaPlayer's current position every 1 second here.
            }

        };

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...