Android MediaPlayer播放完第二首歌曲后无响应问题如何修复?
问题原因
- 监听丢失问题:
OnCompletionListener仅在onCreate中给首次初始化的MediaPlayer设置了,后续playSong方法中新建的MediaPlayer实例没有重新绑定该监听,第二首歌曲播放完成后没有触发切换逻辑,同时相关状态更新逻辑失效导致应用无响应。 - Handler泄漏与空指针风险:onCreate中启动的循环延时任务没有做生命周期管理,MediaPlayer被释放后任务仍在执行,调用
mediaPlayer.getCurrentPosition()会抛出IllegalStateException异常,触发ANR。 - MediaPlayer操作逻辑不规范:
playSong中对旧MediaPlayer的操作顺序有误,释放前没有判断实例状态,若已经处于停止/释放状态调用stop会直接崩溃。 - 静态实例风险:MediaPlayer被声明为static,容易持有Activity上下文导致内存泄漏,也会增加状态管理混乱的概率。
修复方案
1. 新增类成员变量,统一管理循环任务和监听
private Handler seekHandler; private Runnable seekRunnable; // 抽成公共完成监听,避免重复编写逻辑 private MediaPlayer.OnCompletionListener completionListener = new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if (loop) { playSong(position); } else { nextButton.performClick(); } } };
2. 改造onCreate中的进度更新逻辑
删除原来冗余的Player.this.runOnUiThread进度更新代码,替换为可管理的Handler循环:
// 原来的handler.postDelayed逻辑替换为下面的代码 seekHandler = new Handler(); seekRunnable = new Runnable() { @Override public void run() { // 增加实例状态判断,避免调用异常 if(mediaPlayer != null && mediaPlayer.isPlaying()){ int currentPos = mediaPlayer.getCurrentPosition(); seekMusic.setProgress(currentPos); txtsstart.setText(evalTime(currentPos)); } seekHandler.postDelayed(this, 500); } }; seekHandler.postDelayed(seekRunnable, 500); // 首次创建MediaPlayer后绑定公共监听 mediaPlayer.setOnCompletionListener(completionListener);
3. 重写onDestroy方法,释放资源避免泄漏
@Override protected void onDestroy() { super.onDestroy(); // 销毁时停止循环任务 if (seekHandler != null) { seekHandler.removeCallbacks(seekRunnable); seekHandler = null; } // 释放MediaPlayer资源 if (mediaPlayer != null) { if(mediaPlayer.isPlaying()){ mediaPlayer.stop(); } mediaPlayer.release(); mediaPlayer = null; } }
4. 重构playSong方法,规范操作逻辑
public void playSong(int pos){ // 先停止当前的进度更新任务,避免操作旧实例抛出异常 if (seekHandler != null) { seekHandler.removeCallbacks(seekRunnable); } // 规范释放旧MediaPlayer逻辑 if(mediaPlayer != null){ if(mediaPlayer.isPlaying()){ mediaPlayer.stop(); } mediaPlayer.release(); mediaPlayer = null; } Uri u = Uri.parse(mySongs.get(pos).toString()); mediaPlayer = MediaPlayer.create(getApplicationContext(), u); sname = mySongs.get(pos).getName(); txtsname.setText(sname); seekMusic.setMax(mediaPlayer.getDuration()); String endTime = evalTime(mediaPlayer.getDuration()); txtsstop.setText(endTime); // 给新的MediaPlayer绑定完成监听 mediaPlayer.setOnCompletionListener(completionListener); mediaPlayer.start(); playButton.setImageResource(R.drawable.ic_pause); setAlbumCover(); // 重新启动进度更新任务 seekHandler.postDelayed(seekRunnable, 500); }
内容的提问来源于stack exchange,提问作者Masaneo
相关产品推荐
相关产品推荐

