Android MediaPlayer在SDK<24版本恢复播放时崩溃求助
解决低版本SDK(<24)下MediaPlayer空指针崩溃问题
嘿,我帮你捋捋这个低版本SDK下MediaPlayer空指针的问题——我之前也碰到过类似的坑,大概率是状态管理和初始化时机在低版本下的严格要求导致的。SDK24及以上对MediaPlayer的状态校验做了优化,但低版本里稍不注意就会踩空指针的坑,咱们一步步来解决:
核心原因分析
低版本Android(<24)中MediaPlayer的状态机更敏感,而且系统对后台资源的回收更激进:
- 如果你的
mMediaPlayer实例化时机晚于监听器设置,或者在Activity后台被回收后没有重新初始化,就会触发空指针; onResume时直接调用start(),没有先检查mMediaPlayer是否处于有效状态(比如是否被释放、是否已准备好)。
具体解决方案
1. 确保MediaPlayer初始化时机正确
把mMediaPlayer的实例化放在所有操作之前,并且用异步准备避免阻塞主线程,同时添加异常兜底:
private MediaPlayer mMediaPlayer; private int mLastPosition = 0; private String path; // 你的视频路径 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_player); // 先恢复上次保存的播放位置(如果有) if (savedInstanceState != null) { mLastPosition = savedInstanceState.getInt("last_play_position", 0); } // 优先实例化MediaPlayer,再执行后续配置 initMediaPlayer(); } // 把初始化逻辑抽成独立方法,方便复用 private void initMediaPlayer() { // 先释放旧的实例,避免内存泄漏 if (mMediaPlayer != null) { mMediaPlayer.release(); mMediaPlayer = null; } mMediaPlayer = new MediaPlayer(); try { mMediaPlayer.setOnVideoSizeChangedListener(this); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setDataSource(this, Uri.parse(path)); // 准备完成后自动恢复播放位置 mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { if (mLastPosition > 0) { mp.seekTo(mLastPosition); } mp.start(); } }); mMediaPlayer.setOnCompletionListener(this); // 用异步准备,避免阻塞主线程 mMediaPlayer.prepareAsync(); } catch (Exception e) { e.printStackTrace(); // 这里可以加个用户提示,比如"视频加载失败" } }
2. 优化生命周期中的状态管理
在onPause和onResume中严格校验mMediaPlayer的状态,避免空指针:
@Override protected void onPause() { super.onPause(); // 记录位置前先检查实例是否存在、是否正在播放 if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { mLastPosition = mMediaPlayer.getCurrentPosition(); mMediaPlayer.pause(); } } @Override protected void onResume() { super.onResume(); if (mMediaPlayer != null) { // 检查MediaPlayer是否已准备好,且未在播放 if (mMediaPlayer.isPrepared() && !mMediaPlayer.isPlaying()) { mMediaPlayer.seekTo(mLastPosition); mMediaPlayer.start(); } } else { // 如果实例已被回收,重新初始化 initMediaPlayer(); } }
3. 处理配置变化(比如屏幕旋转)
低版本中屏幕旋转会重建Activity,导致mMediaPlayer被销毁,你可以在Manifest里给Activity添加配置,避免重建:
<activity android:name=".YourPlayerActivity" android:configChanges="orientation|screenSize|keyboardHidden" />
或者在onSaveInstanceState中保存播放位置,重建后恢复:
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("last_play_position", mLastPosition); }
4. 全局空指针防护
在所有使用mMediaPlayer的回调和方法里,都加上非空判断:
@Override public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { if (mMediaPlayer == null) return; // 你的视频尺寸适配逻辑 } @Override public void onCompletion(MediaPlayer mp) { if (mMediaPlayer == null) return; // 播放完成后的逻辑,比如重置位置 mLastPosition = 0; }
最后提醒
低版本SDK下一定要遵循MediaPlayer的状态机规则:未初始化的实例不能调用任何方法,已释放的实例不能复用。每次操作前都检查实例状态,就能避免大部分空指针问题。
内容的提问来源于stack exchange,提问作者user8324061
相关产品推荐
相关产品推荐

