我有两种可以测试游戏的设备:美国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);
更新
我注意到应该播放的声音(但没有)会出现此错误:
AudioPolicyManager: stopOutput() oldDevice 2
AudioPolicyManager: [getDeviceForStrategy] strategy : 0,forceUse(0)
答案 0 :(得分:14)
我遇到了同样的问题,确实是垃圾收集器问题!如果将媒体播放器的实例分配给方法内的某个局部变量,则在离开该方法后该实例不再存在,因此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);
}
};
我希望这会对你有所帮助。
答案 1 :(得分:3)
我已经读过SoundPool类比MediaPlayer更适合这样的短音,但这可能不是问题。 (here's指向SoundPool示例的链接)。
您还可以发布点击处理程序的代码吗?
另外,我建议而不是释放和重新获得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();
答案 2 :(得分: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 :(得分:1)
我遇到了这个问题并解决了它使我的MediaPlayer对象变为私有,因此垃圾收集器不会清理该实例。希望它对某人有帮助!
答案 4 :(得分:0)
这很奇怪,并不是一个好的修复,但是到目前为止我发现的唯一修复。如果我删除mp.setOnPreparedListener
和mp.setOnCompletionListener
并且只有mp.start()
,则可以。