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

Android Studio音乐App开发问题:切换歌曲时停止前一曲播放

嗨,这个问题我之前做音乐App的时候也碰到过!核心原因就是每次打开播放页面(新Activity)都会创建一个全新的播放器实例,之前的播放页面并没有被彻底销毁或者播放器没被停止,导致多个播放器同时在后台工作。下面给你几个实用的解决方案,你可以根据App的复杂度选择:

解决方案1:使用单例模式统一管理播放器

这种方式能保证整个App里只有一个播放器实例,切换歌曲时自动停止之前的播放,非常适合小型音乐App。

先创建一个单例的播放器工具类:

package com.recycler.hp.navigationbar;

import android.media.MediaPlayer;
import android.net.Uri;
import android.content.Context;

public class MediaPlayerHelper {
    // 单例实例
    private static MediaPlayerHelper instance;
    private MediaPlayer mediaPlayer;

    // 私有构造方法,禁止外部创建实例
    private MediaPlayerHelper() {}

    // 获取单例的方法
    public static synchronized MediaPlayerHelper getInstance() {
        if (instance == null) {
            instance = new MediaPlayerHelper();
        }
        return instance;
    }

    // 播放/切换歌曲的方法
    public void playSong(Context context, Uri songUri) {
        try {
            // 如果已有播放器,先停止并释放
            if (mediaPlayer != null) {
                if (mediaPlayer.isPlaying()) {
                    mediaPlayer.stop();
                }
                mediaPlayer.release();
                mediaPlayer = null;
            }
            // 创建新的播放器并播放
            mediaPlayer = MediaPlayer.create(context, songUri);
            mediaPlayer.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 停止播放的方法
    public void stopSong() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
}

然后在你的播放Activity里调用:

// 在播放页面初始化或者触发播放的地方调用
Uri songUri = getIntent().getParcelableExtra("SONG_URI"); // 假设你传递了歌曲的Uri
MediaPlayerHelper.getInstance().playSong(this, songUri);

// 记得在页面销毁时停止播放(可选,防止后台残留播放)
@Override
protected void onDestroy() {
    super.onDestroy();
    MediaPlayerHelper.getInstance().stopSong();
}
解决方案2:用Service管理后台播放(推荐复杂场景)

如果你的App需要后台持续播放、锁屏控制等功能,用Service是更专业的做法,所有播放逻辑都统一在Service里,不受Activity生命周期影响。

先创建一个音乐播放Service:

package com.recycler.hp.navigationbar;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.IBinder;

public class MusicService extends Service {
    private MediaPlayer mediaPlayer;

    @Override
    public IBinder onBind(Intent intent) {
        return null; // 如果不需要绑定,返回null即可
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            // 获取传递过来的歌曲Uri
            Uri songUri = intent.getParcelableExtra("SONG_URI");
            if (songUri != null) {
                playSong(songUri);
            }
        }
        return START_STICKY; // 保证Service被杀死后能重启
    }

    private void playSong(Uri songUri) {
        try {
            // 停止并释放旧的播放器
            if (mediaPlayer != null) {
                if (mediaPlayer.isPlaying()) {
                    mediaPlayer.stop();
                }
                mediaPlayer.release();
                mediaPlayer = null;
            }
            // 创建新播放器并播放
            mediaPlayer = MediaPlayer.create(this, songUri);
            mediaPlayer.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

然后在RecyclerView的点击事件里启动Service(同时可以打开播放页面):

// 点击歌曲时的逻辑
Uri songUri = ...; // 获取当前歌曲的Uri
// 启动播放Service
Intent serviceIntent = new Intent(context, MusicService.class);
serviceIntent.putExtra("SONG_URI", songUri);
context.startService(serviceIntent);
// 打开播放Activity
Intent playIntent = new Intent(context, PlayActivity.class);
context.startActivity(playIntent);
解决方案3:通过广播通知旧页面停止播放

如果不想改动太多现有代码,可以用广播的方式,每次打开新的播放页面时,发送广播通知之前的播放页面停止播放。

首先在播放Activity里注册广播接收器:

package com.recycler.hp.navigationbar;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;

public class PlayActivity extends Activity {
    private MediaPlayer mediaPlayer;
    private BroadcastReceiver stopPlayReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play);

        // 注册广播接收器,接收停止播放的指令
        stopPlayReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // 停止当前播放并释放资源
                if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                    mediaPlayer.stop();
                    mediaPlayer.release();
                    mediaPlayer = null;
                }
            }
        };
        IntentFilter filter = new IntentFilter("com.recycler.hp.navigationbar.ACTION_STOP_PLAY");
        registerReceiver(stopPlayReceiver, filter);

        // 初始化播放当前歌曲
        Uri songUri = getIntent().getParcelableExtra("SONG_URI");
        mediaPlayer = MediaPlayer.create(this, songUri);
        mediaPlayer.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 注销广播接收器
        unregisterReceiver(stopPlayReceiver);
        if (mediaPlayer != null) {
            mediaPlayer.release();
        }
    }
}

然后在RecyclerView的点击事件里,先发送广播再打开新页面:

// 点击歌曲时
Intent stopIntent = new Intent("com.recycler.hp.navigationbar.ACTION_STOP_PLAY");
context.sendBroadcast(stopIntent);
// 打开播放页面
Intent playIntent = new Intent(context, PlayActivity.class);
playIntent.putExtra("SONG_URI", songUri);
context.startActivity(playIntent);

内容的提问来源于stack exchange,提问作者Usama Hameed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:09:07