MediaControllerCompat获取状态无当前位置,如何配置MediaSessionCompat返回最新位置?
解决MediaController.getPlaybackState().getPosition()不更新的问题
嘿,我明白你的困扰——你只在onPlay和onPause时设置了播放位置,所以MediaController拿到的永远是那个固定值,对吧?要让它能获取到实时的播放位置,关键在于要持续更新MediaSessionCompat的PlaybackState,并把更新后的状态同步给所有连接的控制器。下面是具体的实现步骤和代码示例:
核心原理
MediaController的getPlaybackState()拿到的是MediaSession最近一次推送的状态数据。如果你只在播放/暂停时设置位置,那它自然不会自动更新。我们需要:
- 实时获取播放器的当前位置
- 用这个位置更新
PlaybackStateCompat.Builder - 调用
MediaSessionCompat.setPlaybackState()把新状态推送给控制器
具体实现步骤
1. 初始化MediaSession和PlaybackStateBuilder
首先在你的Activity或Service里初始化MediaSession,同时创建一个可复用的PlaybackStateBuilder(避免重复创建对象):
private MediaSessionCompat mMediaSession; private PlaybackStateCompat.Builder mPlaybackStateBuilder; private MediaPlayer mMediaPlayer; // 或者你用的其他播放器,比如ExoPlayer // 在onCreate里初始化 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化MediaSession mMediaSession = new MediaSessionCompat(this, "YourSessionTag"); mMediaSession.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS ); mMediaSession.setActive(true); // 初始化PlaybackStateBuilder,设置支持的操作(播放、暂停、快进等) mPlaybackStateBuilder = new PlaybackStateCompat.Builder() .setActions( PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_SEEK_TO ); }
2. 在播放/暂停时更新基础状态
在MediaSessionCompat.Callback的onPlay和onPause方法里,除了设置播放状态,还要同步当前的播放位置、更新时间和播放速度:
private MediaSessionCompat.Callback mSessionCallback = new MediaSessionCompat.Callback() { @Override public void onPlay() { super.onPlay(); // 启动播放器 mMediaPlayer.start(); // 更新PlaybackState long currentPos = mMediaPlayer.getCurrentPosition(); mPlaybackStateBuilder.setState( PlaybackStateCompat.STATE_PLAYING, currentPos, 1.0f, // 播放速度,1.0是正常速度 System.currentTimeMillis() // 更新状态的时间戳 ); mMediaSession.setPlaybackState(mPlaybackStateBuilder.build()); // 启动实时位置更新(后面会讲) startPositionUpdater(); } @Override public void onPause() { super.onPause(); // 暂停播放器 mMediaPlayer.pause(); // 更新暂停状态的位置 long currentPos = mMediaPlayer.getCurrentPosition(); mPlaybackStateBuilder.setState( PlaybackStateCompat.STATE_PAUSED, currentPos, 0.0f, // 暂停时速度为0 System.currentTimeMillis() ); mMediaSession.setPlaybackState(mPlaybackStateBuilder.build()); // 停止实时位置更新 stopPositionUpdater(); } };
3. 实时更新播放位置
用Handler定时获取播放器的当前位置,并更新MediaSession的状态。这样MediaController就能拿到最新的位置数据了:
private Handler mProgressHandler = new Handler(Looper.getMainLooper()); private Runnable mPositionUpdateRunnable = new Runnable() { @Override public void run() { if (mMediaPlayer.isPlaying()) { long currentPos = mMediaPlayer.getCurrentPosition(); // 更新PlaybackState mPlaybackStateBuilder.setState( PlaybackStateCompat.STATE_PLAYING, currentPos, 1.0f, System.currentTimeMillis() ); mMediaSession.setPlaybackState(mPlaybackStateBuilder.build()); // 每500毫秒更新一次(可根据需求调整间隔) mProgressHandler.postDelayed(this, 500); } } }; // 启动位置更新 private void startPositionUpdater() { stopPositionUpdater(); // 先移除之前的回调,避免重复 mProgressHandler.post(mPositionUpdateRunnable); } // 停止位置更新 private void stopPositionUpdater() { mProgressHandler.removeCallbacks(mPositionUpdateRunnable); }
4. 处理销毁和资源释放
在Activity销毁时,记得清理资源,避免内存泄漏:
@Override protected void onDestroy() { super.onDestroy(); stopPositionUpdater(); mMediaSession.setActive(false); mMediaSession.release(); mMediaPlayer.release(); }
关键注意点
- 播放速度与时间戳:当状态为
STATE_PLAYING时,系统会根据你设置的updateTime(时间戳)和playbackSpeed自动推算当前位置。即使你不每毫秒更新,也能得到相对准确的位置,但定时更新会更精确。 - 播放器兼容性:如果你用的是ExoPlayer,可以通过监听
Player.EventListener的onPositionDiscontinuity或onPlaybackStateChanged来触发更新,比Handler定时更高效。 - 必须调用setPlaybackState:每次更新PlaybackState后,一定要调用这个方法,否则MediaController不会收到更新。
这样设置后,你的MediaController调用mediaController.getPlaybackState().getPosition()时,就能拿到实时的播放位置了。
内容的提问来源于stack exchange,提问作者Ashesh Bharadwaj
相关产品推荐
相关产品推荐

