Android MediaSession架构中Media Player与SeekBar的通信
Android communication between MediaPlayer and SeekBar in MediaSession Architecuture
我正在开发音频流应用程序。我按照 android 描述 here. In my app, I have one activity, MainActivity
, which loads fragments according to selected functions. In one of these fragments, I provide a ReplayPlayer
where I would like to let users seek through the streamed audio, play/pause the stream, etc. I found this 的方式设计了我的应用程序,并设计了我的应用程序,使我的 StreamService
控制 MediaPlayer
,因此 MediaPlayer
为我的应用位于 StreamService
.
问题是我试图将 ReplayPlayer
中的 SeekBar
与 StreamService
中 MediaPlayer
中的媒体相关联。据我了解,MediaBrowserService
不能绑定,不像 Service
,所以我不能在 StreamService
中访问我的 MediaPlayer 的 currentPosition
。所以,我对如何从我的 ReplayPlayer
片段访问这个 MediaPlayer
的 currentPosition
感到困惑。
由于其他音乐播放器应用程序清楚地显示了歌曲中的当前位置,我感觉到有一种方法可以实现我目前正在努力解决的问题。我该怎么做?
在此先感谢您的帮助。
AndroidManifest.xml
<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>
StreamService.java
public class StreamService extends MediaBrowserServiceCompat implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener{
private static final String TAG = "StreamService";
private MediaPlayer mediaPlayer;
private MediaSessionCompat mediaSessionCompat;
private BroadcastReceiver mNoisyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(mediaPlayer != null && mediaPlayer.isPlaying()) mediaPlayer.pause();
}
};
private WifiManager.WifiLock wifiLock;
@Override
public void onCreate() {
super.onCreate();
wifiLock =((WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE)).createWifiLock(WifiManager.WIFI_MODE_FULL, "myLock");
initMediaSession();
initNoisyReceiver();
}
@Override
public void onDestroy() {
super.onDestroy();
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.abandonAudioFocus(this);
unregisterReceiver(mNoisyReceiver);
mediaSessionCompat.release();
if(mediaPlayer!=null) mediaPlayer.release();
stopSelf();
}
private void initMediaSession(){
ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class);
mediaSessionCompat = new MediaSessionCompat(getApplicationContext(), "Tag", mediaButtonReceiver, null);
mediaSessionCompat.setCallback(mediaSessionCallbacks);
mediaSessionCompat.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS );
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setClass(this, MediaButtonReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
mediaSessionCompat.setMediaButtonReceiver(pendingIntent);
setSessionToken(mediaSessionCompat.getSessionToken());
}
private void initNoisyReceiver(){
//Handles headphones coming unplugged. cannot be done through a manifest receiver
IntentFilter filter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(mNoisyReceiver, filter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
MediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) {
if(TextUtils.equals(clientPackageName, getPackageName())) {
return new BrowserRoot(getString(R.string.app_name), null);
}
return null;
}
@Override
public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
result.sendResult(null);
}
private MediaSessionCompat.Callback mediaSessionCallbacks = new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
super.onPlay();
if( !successfullyRetrievedAudioFocus() ) {
return;
}
mediaPlayer.start();
setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING);
}
@Override
public void onPause() {
super.onPause();
if( mediaPlayer.isPlaying() ) {
mediaPlayer.pause();
setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED);
}
}
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
if(mediaPlayer != null) mediaPlayer.release();
super.onPlayFromUri(uri, extras);
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mediaPlayer.setDataSource(uri.toString());
mediaPlayer.setVolume(1.0f, 1.0f);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build());
else // setAudioStreamType deprecated past Oreo
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnPreparedListener(StreamService.this);
setMediaSessionMetadata(extras);
mediaPlayer.prepareAsync();
wifiLock.acquire();
} catch(IOException e) {
e.printStackTrace();
}
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop called");
if(mediaPlayer.isPlaying()) {
mediaPlayer.release();
setMediaPlaybackState(PlaybackStateCompat.STATE_STOPPED);
}
}
};
@Override
public void onPrepared(MediaPlayer mp) {
Log.d(TAG, "mediaPlayer prepared");
mediaSessionCompat.setActive(true);
mediaPlayer.start();
setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING);
successfullyRetrievedAudioFocus();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp = null;
wifiLock.release();
return false;
}
@Override
public void onCompletion(MediaPlayer mp) {
if(mp != null) mp.release();
}
@Override
public void onAudioFocusChange(int focusChange) {
switch( focusChange ) {
case AudioManager.AUDIOFOCUS_LOSS: {
Log.d(TAG, "audio focus loss");
if( mediaPlayer.isPlaying() ) {
mediaPlayer.stop();
}
break;
}
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: {
Log.d(TAG, "audio focus loss transient");
mediaPlayer.pause();
break;
}
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: {
Log.d(TAG, "audio focus loss transient can duck");
if( mediaPlayer != null ) {
mediaPlayer.setVolume(0.3f, 0.3f);
}
break;
}
case AudioManager.AUDIOFOCUS_GAIN: {
Log.d(TAG, "audio focus gain");
if( mediaPlayer != null ) {
if( !mediaPlayer.isPlaying() ) {
mediaPlayer.start();
}
mediaPlayer.setVolume(1.0f, 1.0f);
}
break;
}
}
}
private boolean successfullyRetrievedAudioFocus() {
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
AudioAttributes attr = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TY PE_MUSIC).build();
int result = -1;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
result = audioManager.requestAudioFocus(new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).setAudioAttributes(attr).setAcceptsDelayedFocusGain(true).setOnAudioFocusChangeListener(this).build());
synchronized(this) {
return result==AudioManager.AUDIOFOCUS_GAIN;
}
} else {
result = audioManager.requestAudioFocus(this, AudioAttributes.CONTENT_TYPE_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
return result == AudioManager.AUDIOFOCUS_GAIN;
}
}
private void setMediaPlaybackState(int state) {
PlaybackStateCompat.Builder playbackstateBuilder = new PlaybackStateCompat.Builder();
if( state == PlaybackStateCompat.STATE_PLAYING ) {
playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PAUSE);
} else {
playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY);
}
playbackstateBuilder.setState(state, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 0);
mediaSessionCompat.setPlaybackState(playbackstateBuilder.build());
}
private void setMediaSessionMetadata(Bundle extras) {
MediaMetadataCompat.Builder metadataBuilder = new MediaMetadataCompat.Builder();
if(extras.getParcelable("Track")!=null) {
Track track = extras.getParcelable("Track");
Log.d(TAG, String.valueOf(track.getID()));
metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, String.valueOf(track.getID()));
metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_ART, track.getArtworkURL());
metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, track.getTitle());
metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI, track.getStreamURL());
metadataBuilder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, track.getDuration());
}
mediaSessionCompat.setMetadata(metadataBuilder.build());
}
}
您可以 post 在服务端的 MediaSessionCompat 中更新您的 MediaPlayer 的位置,然后在您的片段中您将在 MediaControllerCompat.Callback 的 onPlaybackStateChanged(PlaybackStateCompat state) 方法中收到播放状态更新。
使用处理程序 post 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(元数据)设置媒体文件的总持续时间。
MediaMetadataCompat mediaMetadata = new MediaMetadataCompat.Builder()
.putString(MediaMetadata.METADATA_KEY_TITLE, "XYZ"))
.putLong(MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration())
.build();
在您的 Fragment/Activity 中,您可以使用 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.
}
};
我正在开发音频流应用程序。我按照 android 描述 here. In my app, I have one activity, MainActivity
, which loads fragments according to selected functions. In one of these fragments, I provide a ReplayPlayer
where I would like to let users seek through the streamed audio, play/pause the stream, etc. I found this 的方式设计了我的应用程序,并设计了我的应用程序,使我的 StreamService
控制 MediaPlayer
,因此 MediaPlayer
为我的应用位于 StreamService
.
问题是我试图将 ReplayPlayer
中的 SeekBar
与 StreamService
中 MediaPlayer
中的媒体相关联。据我了解,MediaBrowserService
不能绑定,不像 Service
,所以我不能在 StreamService
中访问我的 MediaPlayer 的 currentPosition
。所以,我对如何从我的 ReplayPlayer
片段访问这个 MediaPlayer
的 currentPosition
感到困惑。
由于其他音乐播放器应用程序清楚地显示了歌曲中的当前位置,我感觉到有一种方法可以实现我目前正在努力解决的问题。我该怎么做?
在此先感谢您的帮助。
AndroidManifest.xml
<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>
StreamService.java
public class StreamService extends MediaBrowserServiceCompat implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener{
private static final String TAG = "StreamService";
private MediaPlayer mediaPlayer;
private MediaSessionCompat mediaSessionCompat;
private BroadcastReceiver mNoisyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(mediaPlayer != null && mediaPlayer.isPlaying()) mediaPlayer.pause();
}
};
private WifiManager.WifiLock wifiLock;
@Override
public void onCreate() {
super.onCreate();
wifiLock =((WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE)).createWifiLock(WifiManager.WIFI_MODE_FULL, "myLock");
initMediaSession();
initNoisyReceiver();
}
@Override
public void onDestroy() {
super.onDestroy();
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.abandonAudioFocus(this);
unregisterReceiver(mNoisyReceiver);
mediaSessionCompat.release();
if(mediaPlayer!=null) mediaPlayer.release();
stopSelf();
}
private void initMediaSession(){
ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class);
mediaSessionCompat = new MediaSessionCompat(getApplicationContext(), "Tag", mediaButtonReceiver, null);
mediaSessionCompat.setCallback(mediaSessionCallbacks);
mediaSessionCompat.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS );
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setClass(this, MediaButtonReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
mediaSessionCompat.setMediaButtonReceiver(pendingIntent);
setSessionToken(mediaSessionCompat.getSessionToken());
}
private void initNoisyReceiver(){
//Handles headphones coming unplugged. cannot be done through a manifest receiver
IntentFilter filter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(mNoisyReceiver, filter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
MediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) {
if(TextUtils.equals(clientPackageName, getPackageName())) {
return new BrowserRoot(getString(R.string.app_name), null);
}
return null;
}
@Override
public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
result.sendResult(null);
}
private MediaSessionCompat.Callback mediaSessionCallbacks = new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
super.onPlay();
if( !successfullyRetrievedAudioFocus() ) {
return;
}
mediaPlayer.start();
setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING);
}
@Override
public void onPause() {
super.onPause();
if( mediaPlayer.isPlaying() ) {
mediaPlayer.pause();
setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED);
}
}
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
if(mediaPlayer != null) mediaPlayer.release();
super.onPlayFromUri(uri, extras);
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mediaPlayer.setDataSource(uri.toString());
mediaPlayer.setVolume(1.0f, 1.0f);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build());
else // setAudioStreamType deprecated past Oreo
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnPreparedListener(StreamService.this);
setMediaSessionMetadata(extras);
mediaPlayer.prepareAsync();
wifiLock.acquire();
} catch(IOException e) {
e.printStackTrace();
}
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop called");
if(mediaPlayer.isPlaying()) {
mediaPlayer.release();
setMediaPlaybackState(PlaybackStateCompat.STATE_STOPPED);
}
}
};
@Override
public void onPrepared(MediaPlayer mp) {
Log.d(TAG, "mediaPlayer prepared");
mediaSessionCompat.setActive(true);
mediaPlayer.start();
setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING);
successfullyRetrievedAudioFocus();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp = null;
wifiLock.release();
return false;
}
@Override
public void onCompletion(MediaPlayer mp) {
if(mp != null) mp.release();
}
@Override
public void onAudioFocusChange(int focusChange) {
switch( focusChange ) {
case AudioManager.AUDIOFOCUS_LOSS: {
Log.d(TAG, "audio focus loss");
if( mediaPlayer.isPlaying() ) {
mediaPlayer.stop();
}
break;
}
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: {
Log.d(TAG, "audio focus loss transient");
mediaPlayer.pause();
break;
}
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: {
Log.d(TAG, "audio focus loss transient can duck");
if( mediaPlayer != null ) {
mediaPlayer.setVolume(0.3f, 0.3f);
}
break;
}
case AudioManager.AUDIOFOCUS_GAIN: {
Log.d(TAG, "audio focus gain");
if( mediaPlayer != null ) {
if( !mediaPlayer.isPlaying() ) {
mediaPlayer.start();
}
mediaPlayer.setVolume(1.0f, 1.0f);
}
break;
}
}
}
private boolean successfullyRetrievedAudioFocus() {
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
AudioAttributes attr = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TY PE_MUSIC).build();
int result = -1;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
result = audioManager.requestAudioFocus(new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).setAudioAttributes(attr).setAcceptsDelayedFocusGain(true).setOnAudioFocusChangeListener(this).build());
synchronized(this) {
return result==AudioManager.AUDIOFOCUS_GAIN;
}
} else {
result = audioManager.requestAudioFocus(this, AudioAttributes.CONTENT_TYPE_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
return result == AudioManager.AUDIOFOCUS_GAIN;
}
}
private void setMediaPlaybackState(int state) {
PlaybackStateCompat.Builder playbackstateBuilder = new PlaybackStateCompat.Builder();
if( state == PlaybackStateCompat.STATE_PLAYING ) {
playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PAUSE);
} else {
playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY);
}
playbackstateBuilder.setState(state, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 0);
mediaSessionCompat.setPlaybackState(playbackstateBuilder.build());
}
private void setMediaSessionMetadata(Bundle extras) {
MediaMetadataCompat.Builder metadataBuilder = new MediaMetadataCompat.Builder();
if(extras.getParcelable("Track")!=null) {
Track track = extras.getParcelable("Track");
Log.d(TAG, String.valueOf(track.getID()));
metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, String.valueOf(track.getID()));
metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_ART, track.getArtworkURL());
metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, track.getTitle());
metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI, track.getStreamURL());
metadataBuilder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, track.getDuration());
}
mediaSessionCompat.setMetadata(metadataBuilder.build());
}
}
您可以 post 在服务端的 MediaSessionCompat 中更新您的 MediaPlayer 的位置,然后在您的片段中您将在 MediaControllerCompat.Callback 的 onPlaybackStateChanged(PlaybackStateCompat state) 方法中收到播放状态更新。 使用处理程序 post 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(元数据)设置媒体文件的总持续时间。
MediaMetadataCompat mediaMetadata = new MediaMetadataCompat.Builder()
.putString(MediaMetadata.METADATA_KEY_TITLE, "XYZ"))
.putLong(MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration())
.build();
在您的 Fragment/Activity 中,您可以使用 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.
}
};