在Android中跨多个活动播放背景音乐

32

你好!第一次在stackoverflow上提问,很激动!哈哈。

我们正在开发一个Android游戏,在我们的引导界面(Intro Activity)播放一些背景音乐,但我们希望它能继续播放到下一个Activity,并且可能可以从应用程序的任何地方停止或重新播放音乐。

目前我们做的是在Intro Activity中使用MediaPlayer播放背景音乐。但是,一旦用户离开该Activity,我们就会停止播放音乐。我们需要像Services这样的东西吗?还是MediaPlayer / SoundPool就足够了?如果有人知道答案,我们将非常感谢您的分享。谢谢!


1
我刚遇到了同样的问题,不知道你是如何知道何时停止音乐的?如果在onDestroy中停止服务,则会在子活动之间停止它 - 你怎么知道最后一个游戏活动关闭以停止音乐呢? - Tom
6个回答

10

您也可以创建一个使用MediaPlayer播放音乐的服务,如下所示。

Intent svc=new Intent(this, BackgroundSoundService.class);
startService(svc); //OR stopService(svc); 

public class BackgroundSoundService extends Service {
    private static final String TAG = null;
    MediaPlayer player;
    public IBinder onBind(Intent arg0) {

        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();


        player = MediaPlayer.create(this, R.raw.idil);
        player.setLooping(true); // Set looping
        player.setVolume(100,100);

    }
    public int onStartCommand(Intent intent, int flags, int startId) {


        player.start();

        return 1;
    }

    public void onStart(Intent intent, int startId) {
        // TODO



    }
    public IBinder onUnBind(Intent arg0) {
        // TODO Auto-generated method stub

        return null;
    }

    public void onStop() {

    }
    public void onPause() {

    }
    @Override
    public void onDestroy() {

        player.stop();
        player.release();
    }

    @Override
    public void onLowMemory() {

    }
}

6
创建一个静态的SoundManager,可以使用SoundPools或MediaPlayers。
创建一个名为keepMusicGoing的静态标志。
在第一个活动创建时开始播放音乐。
切换活动时将keepMusicGoing设置为true。
在活动的onStop事件中检查keepMusicGoing是否为true,如果是,则保持音乐播放,并将keepMusicGoing设置为false。
如果按下home按钮,keepMusicGoing标记将为false,因此当活动失去焦点时音乐将停止。
给我发电子邮件,我可以给您发送两个我编写的SoundManager,一个使用MediaPlayers,另一个使用SoundPools。
Chad

1
是的,这也是我们的做法。vladikoff发布了链接,介绍了使用静态管理器来处理音乐的想法来源。 - jhie
嗨 Chad,你能给我发那些例子吗?我的电子邮件地址是sourabhrustagi1@gmail.com - Sourabh
我在这个方法中遇到了问题。我的应用程序支持旋转,当设备旋转时,onStop被调用,并且当用户按下home键时也会被调用。旋转时,我不想停止音乐,但是当按下home键时,我需要停止音乐,不知道如何区分这两个事件,有什么想法吗? - marchinram
太棒了!有点难理解,但是非常好用!感谢分享! - Nick

2

如果我正确理解了您的情况,那么我曾经遇到过同样的问题。我在应用程序中使用不同的线程来播放音乐。这个实现方法传递了一个静态引用给一个Context,我知道这个Context会在音乐播放期间一直存在。

public class AudioPlayer extends Thread {
private Context c;
private Thread blinker;
private File file;

public AudioPlayer (Context c, File file) {
    this.c = c;
    this.file = file;
}

public void go () {
    blinker = this;
    if(!blinker.isAlive()) {
        blinker.start();
    }
}

public void end () {
    Thread waiter = blinker;
    blinker = null;
    if (waiter != null)
        waiter.interrupt ();
}

public void run () {
    MediaPlayer ap = MediaPlayer.create(c, Uri.fromFile(file));
    int duration = ap.getDuration();
    long startTime = System.currentTimeMillis();
    ap.start();
    try {
        Thread thisThread = Thread.currentThread();
        while (this.blinker == thisThread && System.currentTimeMillis() - startTime < duration) {           
            Thread.sleep (500);  // interval between checks (in ms)
        }
        ap.stop ();
        ap.release ();
        ap = null;
    } catch (InterruptedException e) {
        Log.d("AUDIO-PLAYER", "INTERRUPTED EXCEPTION");
        ap.stop ();
        ap.release();
        ap = null;
    }
    }
}

2

首先,我使用了Chad提供的“keepMusicPlaying”标志的方法。但我认为在您的活动的onStart和onStop方法中调用SoundManager类的一些onStart和onStop方法更加优雅。

创建一个自己的类"SoundManager",并从所有活动的onStart和onStop中调用它的一些方法(或使用基础活动类)。通过startCounter(在onStart中使用startCounter++,在onStop中使用startCounter--)来跟踪onStart和onStop。因为新活动的开始在旧活动的onStop之前被调用,所以您总是知道onStart是否是第一次调用(startCounter == 1),还是从您的其他活动中启动的(startCounter == 2)。onStop也是同理(startCounter == 0表示应用已关闭,startCounter == 1表示仅停止了旧活动,但有一个新活动)。

这样,您将所有内容封装到SoundManager中,而不必在应用程序内的每个活动启动时调用一些keepMusicPlaying方法/标志。

    public void OnStart()
    {
        startCounter++;
        if (startCounter == 1)
        {
            //start music here
        }

    public void OnStop()
    {
        startCounter--;
        if (startCounter == 0)
        {
            // stop music here
        }
    }

1

你可以尝试使用AsyncPlayer,但是为了停止声音播放,你应该保留对该类的引用。

你可以使用Uri uri = Uri.parse("android.resource://com.stackoverlof.android/raw/beep.mp3");来创建指向本地资源的Uri。

希望这能帮到你。


0
通过结合 Chad 和 Kedu 的答案并加入我的个人风格,我创建了这个可行的解决方案:
// Parent Activity which every Activity extends
public class ParentActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Music.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();
        Music.onStop();
    }
}

// Controller class for handling background music
public abstract class Music {

    private static MediaPlayer mediaPlayer;
    private static int startCounter = 0;

    public static void onStart() {
        startCounter++;
        if (startCounter == 1) {
            mediaPlayer = MediaPlayer.create(InitializeActivity.getContext(), R.raw.background_music);
            mediaPlayer.setLooping(true);
            mediaPlayer.setVolume(1f, 1f);
            mediaPlayer.start();
        }
    }

    public static void onStop() {
        startCounter--;
        if (startCounter == 0) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }
}

就是这样,超级简单!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接