You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MediaControllerCompat获取状态无当前位置,如何配置MediaSessionCompat返回最新位置?

解决MediaController.getPlaybackState().getPosition()不更新的问题

嘿,我明白你的困扰——你只在onPlay和onPause时设置了播放位置,所以MediaController拿到的永远是那个固定值,对吧?要让它能获取到实时的播放位置,关键在于要持续更新MediaSessionCompat的PlaybackState,并把更新后的状态同步给所有连接的控制器。下面是具体的实现步骤和代码示例:

核心原理

MediaController的getPlaybackState()拿到的是MediaSession最近一次推送的状态数据。如果你只在播放/暂停时设置位置,那它自然不会自动更新。我们需要:

  1. 实时获取播放器的当前位置
  2. 用这个位置更新PlaybackStateCompat.Builder
  3. 调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:13:16