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

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延迟任务未移除:播放时启动的UpdateSongTime Runnable循环未在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:37:12