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
相关产品推荐
相关产品推荐

