等待循环中的事件侦听器?

时间:2016-05-14 18:58:21

标签: java android concurrency

我有一个控制器类,需要对列表中的每个项执行各种异步操作:

    每个A
    • 播放音频并等待完成
    • 等待 t
    • 对于A的每个子部分B:
      • 播放音频并等待
      • 等待 t2

我知道当我的OnCompletionListener.onCompletion方法被触发时音频已经完成,并且当我的CountDownTimer.onFinish()方法被触发时我知道计时器何时完成。我试过回复听众:

for (final A a : getAs()) {
   show(a);
   playAudio(a.audioBegin, new MediaPlayer.OnCompletionListener() {
     @Override
     public void onCompletion(MediaPlayer mp) {
       wait(a.secs, new OnFinishListener() {
         @Override
         public void onFinish() {
           if (a.hasSubparts) {
             for (final B b : a.getBs()) {
               playAudio(b.audioBegin, new MediaPlayer.OnCompletionListener() {
               ...
       }
     }
   }
}

但最后我无法摆脱内循环,这让我觉得这整个想法都行不通。我查看了Future界面,但这似乎也不是我想要的。

我知道我可以用一堆变量来解决这个问题,以便跟踪我在状态流中的位置,但是使用某个框架的循环会更清晰。谢谢:))

1 个答案:

答案 0 :(得分:0)

这种任务听起来像是RxJava的好地方。

请查看此post,它会向您展示如何将MediaPlayer包装为使用Rx。

我会使用timer运算符来确定您感兴趣的延迟,并From运算符逐个查看您的列表。

祝你好运

编辑:这是用rxJava做的一种方法,但是这是一个简化版本,一旦你能更好地理解rxJava,你可以稍微好一点,例如包装回调,替换主题机制,处理错误等等上。

所以,首先我们将制作一个可播放对象的平面列表,我假设A和B对象有一个共同的父对象,因为A实际上有更多的方法然后B我假定这个结构:

private interface B {
    Object audioBegin();
    long getWaitSecs();
}

private interface A extends B {
    boolean hasSubparts();
    List<B> getBs();
}

所以为了观察播放列表我们会这样做:

    //this will create a flat play list
    List<B> flatPlayList = new ArrayList<>();
    for ( A a : getAs()){
       flatPlayList.add(a);
       if ( a.hasSubparts()){
           for (B b : a.getBs()){
               flatPlayList.add(b);
           }
       }
    }
    //just creating an observable out of it
    Observable<B> playListObservable = Observable.from(flatPlayList);

现在我们有一个播放列表,我们需要一个接一个地播放它,但是等待前一个完成+等待,为此我们将使用一个主题:

    //this will be used to inform every time an audio has completed playing after a wait
    final PublishSubject<Void> onCompleteSubject = PublishSubject.create();

并一起修补:

//zip will send the next B on the list every time there was an audio completion
    Observable.zip(playListObservable, onCompleteSubject, new Func2<B, Void, B>() {
        @Override
        public B call(B b, Void aVoid) {
            return b;
        }
    }).subscribe(new Action1<B>() {
        @Override
        public void call(final B b) {
            //play the actual audio
            playAudio(b.audioBegin(), new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    //audio has completed playing, so we will wait sec as needed then infrom that we completed;
                    Observable.timer(b.getWaitSecs(), TimeUnit.SECONDS).subscribe(new Action1<Long>() {
                        @Override
                        public void call(Long aLong) {
                            onCompleteSubject.onNext(null);
                        }
                    });
                }
            });
        }
    });

最后,因为第一个项目在完成事件之前不会开始播放,我们只会发送一个来启动整个事件链:

onCompleteSubject.onNext(null); //will cause to start playing