在继续之前等待声音完成

时间:2017-10-23 23:32:42

标签: java android for-loop audio android-mediaplayer

我正在创建一个循环遍历字符串的循环,并根据存在的字符播放不同的声音。不幸的是,它不会等待声音在继续之前完成,这会引起媒体播放器的错误。我的循环看起来像这样:

 data-ng-init="iframeLoaded()"

我的播放器看起来像这样:

$scope.iframeLoaded = function() {
    $('#contentPage').css('background', 'none');
};

我不确定如何在继续循环中的下一个字符之前等待完成侦听器。

1 个答案:

答案 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将不可避免地导致系统耗尽这些短声音的资源。