4

我正在尝试编写一个函数来在我的程序中播放短声音(在 /res/raw 中),在整个程序中有效地随机调用。到目前为止,我有这个功能:

public void playSound() {
    MediaPlayer mp = new MediaPlayer();
    mp = MediaPlayer.create(this, R.raw.ShortBeep);
    mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mp.setLooping(false);
    mp.start();
}

它可以正常工作一段时间,但在播放了 30 次之后,它就停止发出声音了。

4

2 回答 2

8

根据文档

...未能调用 release() 可能会导致 MediaPlayer 对象的后续实例回退到软件实现或完全失败。

完成后调用它mp.release()以便它可以释放资源。我不知道限制是什么,我相信这取决于许多因素。无论哪种方式,你都应该在你的MediaPlayer对象上调用这个函数,特别是如果它会被多次使用。

于 2013-09-12T20:19:02.837 回答
1

我刚刚解决了完全相同的问题,但我使用的是 Xamarin。我最终从在活动的整个生命周期中保留一个 MediaPlayer 实例变为每次我想播放声音时都创建一个实例。我还实现了 IOnPreparedListener 和 IOnCompletionListener。

尽管它是 C# 代码,但希望你能得到这个想法

public class ScanBarcodeView :
    MvxActivity,
    MediaPlayer.IOnPreparedListener,
    MediaPlayer.IOnCompletionListener
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.ScanBarcodeView);

        ((ScanBarcodeViewModel) ViewModel).BarcodeScanFailed += (sender, args) => PlaySound(Resource.Raw.fail);
        ((ScanBarcodeViewModel) ViewModel).DuplicateScan += (sender, args) => PlaySound(Resource.Raw.tryagain);
    }

    private void PlaySound(int resource)
    {
        var mp = new MediaPlayer();
        mp.SetDataSource(ApplicationContext, Android.Net.Uri.Parse($"android.resource://com.company.appname/{resource}"));
        mp.SetOnPreparedListener(this);
        mp.SetOnCompletionListener(this);
        mp.PrepareAsync();
    }

    public void OnPrepared(MediaPlayer mp)
    {
        mp.Start();
    }

    public void OnCompletion(MediaPlayer mp)
    {
        mp.Release();
    }
}

因此,每次我想要播放声音时,我都会创建一个 MediaPlayer 实例,因此数据源告诉它我的 Activity 是 Prepared 和 Completion 事件的侦听器并准备它。由于我使用的是 PrepareAsync,因此我不会阻止 UI 线程。当准备好媒体播放器时,调用 MediaPlayer 上的 Start 方法,并在声音播放完毕时释放 MediaPlayer 对象。

在我进行这些更改之前,我会播放 30 种声音,但它们都会停止工作。现在我已经 30 多岁了,也可以同时播放多个声音。

希望有帮助。

于 2017-11-03T10:48:03.733 回答