Android双MediaPlayer实例场景下,如何避免歌曲切换时音频重叠?
如何避免切换歌曲时的音频重叠问题
我有两个Android类:
MusicListScreen:实现了曲目列表的RecyclerViewPlayMusicScreen:通过MediaPlayer实现曲目播放控制
目前两个类各有一个MediaPlayer实例,用户切换歌曲时会出现音频重叠的问题,该怎么解决?
现有代码
MusicListScreen的点击事件代码
@Override public void onRecItemClick(TrackResponse.Results track, int position, Activity context) { Intent intent = new Intent(context, PlayMusicScreen.class); intent.putParcelableArrayListExtra("trackList", mainCategoryList); intent.putExtra("position",position); if(mediaPlayer.isPlaying() && mediaPlayer!=null){ mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer=null; } changeSelectedSong(position); context.startActivity(intent); }
PlayMusicScreen的核心代码
trackList= (ArrayList<TrackResponse.Results>) getIntent().getSerializableExtra("trackList"); int position = getIntent().getIntExtra("position",0); prepareTrack(trackList.get(position)); } public void prepareTrack (TrackResponse.Results trackItem) { String trackLink = trackItem.getAudio(); Glide.with(this) .load(trackItem.getImage()) .apply(requestOptions) .into(songArt); playButton.setImageDrawable(getResources().getDrawable(R.drawable.pause_btn)); if(mediaPlayer.isPlaying() && mediaPlayer!=null){ mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer=null; } try { if (trackItem.getAudio() == null) { Toast.makeText(this, "audio not found", Toast.LENGTH_SHORT); } else { mediaPlayer.setDataSource(trackLink); mediaPlayer.prepare(); mediaPlayer.start(); } } catch (IOException e) { Toast.makeText(this, "audio not found", Toast.LENGTH_SHORT); throw new RuntimeException(e); } handler2.postDelayed(new Runnable() { @Override public void run() { } }, 4000); pushPlay(); pushPrevious(); pushNext(); }
解决方案
1. 全局共享MediaPlayer实例(单例模式)
创建统一的MediaPlayer管理类,让两个页面共用同一个实例,从根源避免多实例同时播放:
public class MediaPlayerManager { private static MediaPlayer mediaPlayer; // 获取全局播放器实例 public static MediaPlayer getInstance() { if (mediaPlayer == null) { mediaPlayer = new MediaPlayer(); } return mediaPlayer; } // 统一停止并释放播放器资源 public static void releasePlayer() { // 先判空再检查播放状态,避免空指针 if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.stop(); } if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } }
2. 修改现有代码使用全局实例
MusicListScreen点击事件修改
@Override public void onRecItemClick(TrackResponse.Results track, int position, Activity context) { Intent intent = new Intent(context, PlayMusicScreen.class); intent.putParcelableArrayListExtra("trackList", mainCategoryList); intent.putExtra("position", position); // 切换前先停止全局播放器 MediaPlayerManager.releasePlayer(); changeSelectedSong(position); context.startActivity(intent); }
PlayMusicScreen的prepareTrack方法修改
public void prepareTrack(TrackResponse.Results trackItem) { String trackLink = trackItem.getAudio(); Glide.with(this) .load(trackItem.getImage()) .apply(requestOptions) .into(songArt); playButton.setImageDrawable(getResources().getDrawable(R.drawable.pause_btn)); // 先停止当前播放 MediaPlayerManager.releasePlayer(); try { if (trackItem.getAudio() == null) { Toast.makeText(this, "未找到音频", Toast.LENGTH_SHORT).show(); } else { MediaPlayer mediaPlayer = MediaPlayerManager.getInstance(); mediaPlayer.setDataSource(trackLink); mediaPlayer.prepare(); mediaPlayer.start(); } } catch (IOException e) { Toast.makeText(this, "音频加载失败", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } pushPlay(); pushPrevious(); pushNext(); }
3. 补充生命周期管理
在PlayMusicScreen销毁时释放播放器,避免内存泄漏:
@Override protected void onDestroy() { super.onDestroy(); MediaPlayerManager.releasePlayer(); }
关键优化点
- 原代码中
if(mediaPlayer.isPlaying() && mediaPlayer!=null)会触发空指针,必须调整为先判空再检查播放状态 - 原Toast未调用
show()方法,无法弹出提示,需补充
内容的提问来源于stack exchange,提问作者Cyclone
相关产品推荐
相关产品推荐

