Mediaplayer即将切断声音

问题描述 投票:11回答:5

[我有两种设备可以在我的游戏上进行测试:美国Celluar手机(SCH-R880)和Kindle Fire,Kindle Fire比手机强大得多。

我有几个短(小于或等于1秒)的声音效果。为了节省内存,我加载,播放和释放其中一些音效。他们在电话上的播放(大多数情况下)符合预期。但是,在Kindle Fire上,它们被缩短了。真的很短的声音被切断,以至于我什么都听不到。那些在安装时加载并保留下来的文件仍然可以正常播放。

任何人都知道这里发生了什么吗?我是否以某种方式过早发布了我的媒体?下面是这种情况的一个实例。在电话上,我听到“第二级!”但是在Kindle上我听到类似“ Lev tw。”的信息。

mpNum = null;

try
{
    switch (level)
    {
        case 2:
            mpNum = MediaPlayer.create(contxt, R.raw.l2); break;
        case 3:
            mpNum = MediaPlayer.create(contxt, R.raw.l3); break;
        case 4:
            mpNum = MediaPlayer.create(contxt, R.raw.l4); break;
        case 5:
            mpNum = MediaPlayer.create(contxt, R.raw.l5); break;
        case 6:
            mpNum = MediaPlayer.create(contxt, R.raw.l6); break;
        case 7:
            mpNum = MediaPlayer.create(contxt, R.raw.l7); break;
        case 8:
            mpNum = MediaPlayer.create(contxt, R.raw.l8); break;
        default:
            return;
    }

    MediaPlayer vLevel = MediaPlayer.create(contxt, R.raw.level);

    vLevel.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
    {
        public void onPrepared(MediaPlayer mp)
        {
            mp.start();
        }
    });

    vLevel.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
    {
           public void onCompletion(MediaPlayer mpl)
           {
            mpNum.start();
            mpl.release();
           }
       });

        mpNum.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
        {
            public void onCompletion(MediaPlayer mp)
            {
                mp.release();
            }
        });
    }
    catch (Exception e) {}

为了尝试解决此问题,我尝试了SoundPool,但是它不起作用;我什么也没听到。以下是我尝试使用SoundPool播放音乐的操作:

SoundPool soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 100);
    soundPool.load(contxt, R.raw.song2, 1);
    AudioManager mgr = (AudioManager)contxt.getSystemService(Context.AUDIO_SERVICE);
    float streamVolumeCurrent = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
    float streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
    float volume =  streamVolumeMax;  

    soundPool.play(1, volume, volume, 1, 5, 2);

UPDATE

我注意到应该播放(但没有播放)的声音出现此错误:

AudioPolicyManager: stopOutput() oldDevice 2
AudioPolicyManager: [getDeviceForStrategy] strategy : 0,forceUse(0)
android android-mediaplayer
5个回答
16
投票

我有同样的问题,这确实是垃圾收集器的问题!如果将媒体播放器的实例分配给方法内的某个局部变量,则该实例离开该方法后将不再存在,因此GC可以随时将其随机删除。

为了避免这种情况,您至少需要在其他地方保留一个指向实例的指针。我创建了一个静态集来保留所有指针,它看起来像这样:

private static Set<MediaPlayer> activePlayers = new HashSet<MediaPlayer>();

然后创建媒体播放器:

MediaPlayer player = MediaPlayer.create(context, context.getResources().getIdentifier(id, "raw", pkg));
activePlayers.add(player);
player.setOnCompletionListener(releaseOnFinishListener);
player.start();

其中releaseOnFinishListener是一个侦听器,它像您一样完全释放媒体播放器,但也从activePlayers集中删除指针:

MediaPlayer.OnCompletionListener releaseOnFinishListener = new MediaPlayer.OnCompletionListener() {
    public void onCompletion(MediaPlayer mp) {
        mp.release();
        activePlayers.remove(mp);
    }
};

希望对您有帮助。


3
投票

好吧,我在一个项目中遇到了同样的问题,这是因为在KindleFire中,声音在完成之前就被剪切掉了,为了解决这个问题(在发布时),我在发布中增加了延迟:

    mpNum.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
    {
        public void onCompletion(MediaPlayer mp)
        {
            // Add a handler delay
            new Timer().schedule(new TimerTask() {

                @Override
                public void run() {
                   mp.release();
               }
            }, DELAY_TIME);
        }
    });

这不是最佳解决方案,但我认为这可能会对您有所帮助。


3
投票

我已经读过SoundPool类比MediaPlayer更适合像这样的短声音,但这可能不是问题。

您还可以为点击处理程序发布代码吗?

另外,我建议不要释放和重新获得MediaPlayer实例,而是使用一个MediaPlayer实例,并在需要重用时遵循典型的reset(),setDataSource(),prepare(),start()序列。这比每次构造一个新实例都要高效。即:

MediaPlayer mp = new MediaPlayer();
AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.sound1);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength();
mp.prepare();
mp.start();

//to reuse
mp.reset();
afd = getResources().openRawResourceFd(R.raw.sound2);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength();
mp.prepare();
mp.start();

1
投票

我遇到了这个问题,并解决了使我的MediaPlayer对象变为私有的问题,因此垃圾收集器不会清理实例。希望对您有所帮助!


0
投票

这很奇怪,不是一个好的解决方案,但是我到目前为止发现的唯一解决方案。如果我删除mp.setOnPreparedListenermp.setOnCompletionListener而只有mp.start(),则可以使用。

© www.soinside.com 2019 - 2024. All rights reserved.