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

Android双MediaPlayer实例场景下,如何避免歌曲切换时音频重叠?

如何避免切换歌曲时的音频重叠问题

我有两个Android类:

  • MusicListScreen:实现了曲目列表的RecyclerView
  • PlayMusicScreen:通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 08:53:34