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

Android天气应用MediaPlayer最小化不停播、切换Fragment重启问题求解

问题根因
  • 前后台切换无法续播:onStop仅暂停播放未存储播放进度,且未在回到前台时恢复播放位置
  • 切Fragment音频重启:当前ViewModel为Fragment级作用域,切走后Fragment销毁重建,LiveData粘性回调触发重复音频初始化逻辑,每次拿到天气数据就销毁重建MediaPlayer
  • 搜索卡顿:每次天气数据回调都重复销毁、重建MediaPlayer,产生不必要的性能消耗
解决步骤

1. 扩展WeatherDataViewModel存储音频状态

在原有WeatherDataViewModel中新增音频状态相关变量和存取方法,避免Fragment销毁后状态丢失:

public class WeatherDataViewModel extends ViewModel {
    // 原有代码保持不变
    // 新增音频状态存储
    private int currentSoundRes = -1;
    private int lastPlayPosition = 0;
    private boolean isPlaying = false;

    public int getCurrentSoundRes() { return currentSoundRes; }
    public void setCurrentSoundRes(int currentSoundRes) { this.currentSoundRes = currentSoundRes; }
    public int getLastPlayPosition() { return lastPlayPosition; }
    public void setLastPlayPosition(int lastPlayPosition) { this.lastPlayPosition = lastPlayPosition; }
    public boolean isPlaying() { return isPlaying; }
    public void setPlaying(boolean playing) { isPlaying = playing; }
    // 原有方法保持不变
}

2. 修改FirstFragment的ViewModel作用域

将Fragment级ViewModel改为Activity级,保证切换Fragment时数据和状态不丢失:

// 原有初始化代码替换为
viewModel = new ViewModelProvider(requireActivity()).get(WeatherDataViewModel.class);

3. 优化音频初始化逻辑

修改LiveData回调中的音频处理逻辑,仅在音频资源变更时才重建MediaPlayer:

// 替换原有soundResource != -1的代码块
if (soundResource != -1) {
    // 仅音频资源变化时才重新初始化播放器
    if (soundResource != viewModel.getCurrentSoundRes()) {
        if (mMediaPlayer != null) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.stop();
            }
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
        viewModel.setCurrentSoundRes(soundResource);
        prepareMediaPlayer(soundResource);
        viewModel.setPlaying(true);
    } else {
        // 音频资源未变化,恢复之前的播放状态
        if (mMediaPlayer != null && !mMediaPlayer.isPlaying() && viewModel.isPlaying()) {
            mMediaPlayer.seekTo(viewModel.getLastPlayPosition());
            mMediaPlayer.start();
        }
    }
}

4. 完善MediaPlayer生命周期管理

重写Fragment的生命周期方法,实现前后台切换的播放状态保存和恢复:

@Override
public void onStart() {
    super.onStart();
    // 回到前台恢复播放
    if (mMediaPlayer != null && !mMediaPlayer.isPlaying() && viewModel.isPlaying()) {
        mMediaPlayer.seekTo(viewModel.getLastPlayPosition());
        mMediaPlayer.start();
    }
}

@Override
public void onStop() {
    super.onStop();
    // 退到后台保存进度并暂停
    if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
        viewModel.setLastPlayPosition(mMediaPlayer.getCurrentPosition());
        mMediaPlayer.pause();
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    // 销毁时释放资源
    if (mMediaPlayer != null) {
        mMediaPlayer.release();
        mMediaPlayer = null;
    }
}

5. 优化Fragment切换逻辑

如果使用ViewPager2承载三个Fragment,在Activity中添加配置避免Fragment销毁:

viewPager2.setOffscreenPageLimit(2);

如果使用FragmentTransaction实现底部导航,将replace方法替换为show/hide组合,避免Fragment实例被销毁重建。


内容的提问来源于stack exchange,提问作者Richard Wilson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 16:36:03