我正在创建一个循环遍历字符串的循环,并根据存在的字符播放不同的声音。不幸的是,它不会等待声音在继续之前完成,这会引起媒体播放器的错误。我的循环看起来像这样:
data-ng-init="iframeLoaded()"
我的播放器看起来像这样:
$scope.iframeLoaded = function() {
$('#contentPage').css('background', 'none');
};
我不确定如何在继续循环中的下一个字符之前等待完成侦听器。
答案 0 :(得分:1)
1)MediaPlayer
不适合这项工作。看看SoundPool
。它适用于重复播放的短音。
2)对于你的情况,你想要的并不是一个循环。声音将以异步方式播放,因此您会遇到这样的情况,即播放的呼叫会堆叠在一起。这将导致MediaPlayer
的本机代码耗尽可用资源。
你想要的是一系列的回调。 MediaPlayer
具有您已经使用的完成回调,但是,虽然这似乎正是所需要的,但它不足以满足您的用例。 MediaPlayer
的本机代码将无法足够快地释放其资源以用于每次后续调用,并且将发生相同的资源耗尽。对于MediaPlayer
的工作原理,这只是一个不幸的现实。
SoundPool
没有那个方便的完成回调,但在这种情况下,你可能只有两个声音样本,你知道它们有多长。一个简单的定时器延迟可能就足够了。您可以使用Handler.postDelayed
来实现此效果。在每个回调事件中,只需播放下一个声音,前进用于跟踪当前声音的任何变量,并再次发布相同的回调以播放任何剩余声音。这是一种异步循环。
更新
为了帮助了解正在发生的事情,请参阅Android Handler
上的文档:
Handler允许您发送和处理与线程的MessageQueue关联的Message和Runnable对象。每个Handler实例都与一个线程和该线程的消息队列相关联。当您创建一个新的Handler时,它被绑定到正在创建它的线程的线程/消息队列 - 从那时起,它将消息和runnables传递给该消息队列并在消息出来时执行它们队列中。
因此,如果我对您的代码结构的猜测接近正确,您将创建一个Handler
对象作为Activity
类的成员。这会将它绑定到GUI线程,这应该没问题,因为你不会在那里做很多工作。您还需要Runnable
作为发布的任务。让它成为你班上的一员。并且您需要包含角色的String
成为会员。您需要int
来跟踪您当前所处的角色。
private Handler playMorseHandler = new Handler();
private String morseChars = ".--...---"; // I don't know where you set this
private int charIndex = 0;
private Runnable playMorseTask = new Runnable() {
if (morseChars == null ||
charIndex < 0 ||
charIndex >= morseChars.length()) {
Log.w("whateverTag", "Basic assumptions failed");
return;
}
char ch = morseChars.charAt(charIndex);
long lengthOfClip = 0L;
boolean postAgain = true;
if (ch == '.') {
Log.d("play: ", "dot");
lengthOfClip = 300L; // I don't know how long your clips are
try {
startPlayback();
} catch (Exception e){
e.printStackTrace();
}
} else if (ch == '-') {
Log.d("play: ", "dash");
lengthOfClip = 500L; // I don't know how long your clips are
try {
startPlayback();
} catch (Exception e){
e.printStackTrace();
}
} else {
Log.d("whateverTag", "unexpected input");
postAgain = false;
}
++charIndex;
if (postAgain && charIndex < morseChars.length()) {
playMorseHandler.postDelayed(this, lengthOfClip);
}
};
无论您想在哪里开始播放声音,只需致电:
charIndex = 0;
playMorseHandler.post(playMorseTask);
唯一剩下的就是让startPlayback()
方法做正确的事情,即使用SoundPool
代替MediaPlayer
。这是因为,正如我之前提到的,MediaPlayer
将不可避免地导致系统耗尽这些短声音的资源。