Android MediaPlayer退出后重进SeekBar跳至末尾问题求助
解决Android MediaPlayer重新进入Activity后SeekBar跳至末尾的问题
问题场景
我通过以下代码实现Android MediaPlayer的播放、暂停、快进/退功能:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_meditatie1); getSupportActionBar().setTitle("Mindfulness"); ColorDrawable colorDrawable = new ColorDrawable(Color.parseColor("#006600")); getSupportActionBar().setBackgroundDrawable(colorDrawable); play_btn=findViewById(R.id.playButton); back_btn=findViewById(R.id.rewindButton); forward_btn=findViewById(R.id.forwardButton); stop_btn=findViewById(R.id.pauseButton); time_txt=findViewById(R.id.textView2); seekBar=findViewById(R.id.seekBar); mediaPlayer= MediaPlayer.create(this, R.raw.mindfulness_pentru_incepatori ); seekBar.setClickable(false); // adding functionalities for the buttons play_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { PlayMusic(); } private void PlayMusic() { mediaPlayer.start(); finalTime=mediaPlayer.getDuration(); startTime=mediaPlayer.getCurrentPosition(); if(oneTimeOnly==0) { seekBar.setMax((int) finalTime); oneTimeOnly=1; } time_txt.setText(String.format( "%d min, %d sec", TimeUnit.MILLISECONDS.toMinutes((long) finalTime), TimeUnit.MILLISECONDS.toSeconds((long) finalTime)- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long)finalTime)) )); seekBar.setProgress((int) startTime); handler.postDelayed(UpdateSongTime, 100); } //creating runnable private Runnable UpdateSongTime=new Runnable() { @Override public void run() { startTime=mediaPlayer.getCurrentPosition(); time_txt.setText(String.format("%d min, %d sec", TimeUnit.MILLISECONDS.toMinutes((long) startTime), TimeUnit.MILLISECONDS.toSeconds((long) startTime) -TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) startTime)))); seekBar.setProgress((int) startTime); handler.postDelayed(this, 100); } }; }); stop_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mediaPlayer.pause(); } }); forward_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int temp=(int) startTime; if((temp+forwardTime) <= finalTime) { startTime=startTime+forwardTime; mediaPlayer.seekTo((int ) startTime); } else { Toast.makeText(Meditatie1.this, "can't make jump", Toast.LENGTH_SHORT).show(); } } }); back_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int temp= (int) startTime; if((temp-backTime)>0) { startTime=startTime-backTime; mediaPlayer.seekTo((int) startTime); } else { Toast.makeText(Meditatie1.this, "Can't go back", Toast.LENGTH_SHORT).show(); } } }); }
为解决按返回键后媒体继续播放的问题,我添加了以下代码:
@Override protected void onDestroy() { super.onDestroy(); if (mediaPlayer != null) { mediaPlayer.stop(); } }
现在媒体能正常停止,但出现新问题:首次进入页面点击播放时SeekBar显示正常,按下返回键退出Activity后重新进入,再次点击播放时SeekBar直接跳至末尾。
问题原因
- 静态成员变量导致状态残留:如果
oneTimeOnly、finalTime等变量被声明为static,退出Activity后这些变量的值不会被重置,重新进入时oneTimeOnly仍为1,导致SeekBar的最大值(max)不会被重新设置为媒体实际时长,此时SeekBar默认max为100,而媒体时长远大于100,设置进度时会被截断到max值,看起来就是跳至末尾。 - MediaPlayer资源未正确释放:
onDestroy中仅调用stop(),未调用release()释放MediaPlayer资源,可能导致资源泄漏,影响新创建的MediaPlayer状态。 - Handler延迟任务未移除:播放时启动的
UpdateSongTimeRunnable循环未在Activity销毁时停止,可能导致旧任务干扰新Activity的UI更新。
解决方案
1. 修正成员变量声明
确保oneTimeOnly、finalTime、startTime等为非静态成员变量,每次创建Activity实例时这些变量都会被初始化为默认值:
// 在类内部声明(非static) private int oneTimeOnly = 0; private long finalTime = 0; private long startTime = 0; private final int forwardTime = 5000; // 快进5秒,可按需调整 private final int backTime = 5000; // 快退5秒,可按需调整 private Handler handler = new Handler();
2. 完善onDestroy方法,正确释放资源并移除任务
在onDestroy中不仅停止MediaPlayer,还要释放资源,并移除Handler的所有延迟任务:
@Override protected void onDestroy() { super.onDestroy(); if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); // 释放MediaPlayer资源 mediaPlayer = null; // 置空避免空指针 } // 移除Handler的所有未执行任务 handler.removeCallbacksAndMessages(null); }
3. 优化PlayMusic方法的SeekBar初始化逻辑
移除oneTimeOnly的判断,每次点击播放时都重新设置SeekBar的max值,避免状态残留:
private void PlayMusic() { mediaPlayer.start(); finalTime = mediaPlayer.getDuration(); startTime = mediaPlayer.getCurrentPosition(); // 每次播放都设置SeekBar的max,确保与媒体时长匹配 seekBar.setMax((int) finalTime); time_txt.setText(String.format( "%d min, %d sec", TimeUnit.MILLISECONDS.toMinutes(finalTime), TimeUnit.MILLISECONDS.toSeconds(finalTime) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(finalTime)) )); seekBar.setProgress((int) startTime); // 先移除旧任务,再添加新任务,避免重复更新 handler.removeCallbacks(UpdateSongTime); handler.postDelayed(UpdateSongTime, 100); }
4. 增加MediaPlayer状态检查(可选)
为避免MediaPlayer在异常状态下出错,可在播放前检查其状态:
private void PlayMusic() { if (mediaPlayer == null) { // 重新创建MediaPlayer(如果之前被释放) mediaPlayer = MediaPlayer.create(this, R.raw.mindfulness_pentru_incepatori); } if (!mediaPlayer.isPlaying()) { mediaPlayer.start(); finalTime = mediaPlayer.getDuration(); startTime = mediaPlayer.getCurrentPosition(); seekBar.setMax((int) finalTime); time_txt.setText(String.format( "%d min, %d sec", TimeUnit.MILLISECONDS.toMinutes(finalTime), TimeUnit.MILLISECONDS.toSeconds(finalTime) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(finalTime)) )); seekBar.setProgress((int) startTime); handler.removeCallbacks(UpdateSongTime); handler.postDelayed(UpdateSongTime, 100); } }
验证效果
修改完成后,重新进入Activity点击播放,SeekBar会正确从0开始更新,不会再跳至末尾,同时返回键退出后MediaPlayer资源被正确释放,无内存泄漏风险。
内容的提问来源于stack exchange,提问作者Patrick Kossik
相关产品推荐
相关产品推荐

