0

下面是我为自定义的一些代码的简化View。它有一个Runnable用于动画和一个Runnable用于音频。该start()函数同时启动可运行的动画和可运行的音频。每个可运行对象都实现了一个带有完成回调的接口。

我需要知道两者什么时候完成,所以我可以打电话给onBothRunnablesFinished().

public class Foo extends View {
  RunnableA mRunnableA;
  RunnableB mRunnableB;

  // overrides of onCreate, onMeasure, onDraw, etc...

  private void onBothRunnablesFinished() {
    // Do stuff when both runnables are finished...
  }

  public void start() {
    mRunnableA = new RunnableA();
    mRunnableB = new RunnableB();
    post(mRunnableA);
    post(mRunnableB);
  }

  private class RunnableA implements Runnable, AnimationListener {
    private MyAnimation mAnim;
    private boolean mRunning = false;

    public RunnableA() {
      mAnim = new MyAnimation();
      mAnim.setAnimationListener(this);
    }

    public boolean isRunning() {
      return mRunning;
    }

    @Override
    public void run() {
      mRunning = true;
      startAnimation(mAnim);
    }

    // Called when mAnim finishes
    @Override
    public void onAnimationEnd(Animation animation) {
      mRunning = false;
      // **WHAT IF THE OTHER RUNNABLE FINISHES NOW?**
      if (mRunnableB.isRunning() == false) {
        onBothRunnablesFinished();
      }
    }
  }

  private class RunnableB implements Runnable, OnCompletionListener {
    private MyMediaPlayer mMediaPlayer;
    private boolean mRunning = false;

    public RunnableB() {
      mMediaPlayer = MyMediaPlayer();
      mMediaPlayer.setOnCompletionListener(this);
    }

    public boolean isRunning() {
      return mRunning;
    }

    @Override
    public void run() {
      mRunning = true;
      mMediaPlayer.start();
    }

    // Called when mMediaPlayer finishes
    @Override
    public void onCompletion(MediaPlayer mp) {
      mRunning == false;
      // **WHAT IF THE OTHER RUNNABLE FINISHES NOW?**
      if (mRunnableA.isRunning() == false) {
        onBothRunnablesFinished();
      }
    }
  }
}

我用评论标记了几个感兴趣的领域。如果音频和动画可运行文件同时完成会发生什么?更具体地说,一个可运行的回调是否会在上面注释的位置中断另一个的回调?这可能吗??

我希望不会,因为 thenonBothRunnablesFinished会被调用两次。如果是这种情况,我该如何解决这个问题?

4

3 回答 3

2

我已经删除了我的另一个答案。现在我考虑一下,您甚至不需要 Runnables,因为动画和媒体播放器框架将使用它们自己的线程。但是,您仍然需要将调用同步到onActivityFinished()(以前称为 onBothRunnablesFinished()),因为框架线程可能同时完成:

public class Foo extends View implements AnimationListener, OnCompletionListener {
    private MyAnimation mAnim;
    private MyMediaPlayer mMediaPlayer;
    private boolean mIsOneActivityFinished = false;

    synchronized private void onActivityFinished() {
        if(!mIsOneActivityFinished) {
             // The first activity is finished. Set the flag and return.
             mIsOneActivityFinished = true;
             return;
        }

        // Do stuff when both activities are finished...
    }

    public void start() {
        mAnim = new MyAnimation();
        mAnim.setAnimationListener(this);
        startAnimation(mAnim);

        mMediaPlayer = MyMediaPlayer();
        mMediaPlayer.setOnCompletionListener(this);
        mMediaPlayer.start();
    }


    // Called when mAnim finishes
    @Override
    public void onAnimationEnd(Animation animation) {
        onActivityFinished();
    }


    // Called when mMediaPlayer finishes
    @Override
    public void onCompletion(MediaPlayer mp) {
        onActivityFinished();
    }
}

相信我,这段代码会起作用,而且更干净。甚至不要考虑使用 Runnables,因为 Android 会为您执行多线程。

巴里

于 2011-07-13T04:17:18.680 回答
1

您可以使用初始化为 2 的 AtomicInteger

并完成运行

if(atomicInt.decrementAndGet()==0)onBothRunnablesFinished();
于 2011-07-13T02:56:06.543 回答
1

我会将 POJO 互斥对象注入到两个可运行对象中,并使用它来同步isRunningonCompletion方法。实际上,isRunning不需要同步,因为它只在 中的同步代码中调用onCompletion,但我认为同步语义更清晰,因为它也同步了。

使用 RunnableA 作为模板(// completion对两个类进行标记):

private class RunnableA implements Runnable, AnimationListener {
  private MyAnimation mAnim;
  private boolean mRunning = false;
  private Object  mExecutionMutex; // completion

  public RunnableA(Object mtx) { // completion
    mAnim = new MyAnimation();
    mAnim.setAnimationListener(this);
    mExecutionMutex=mtx;
  }

  public boolean isRunning() {
    synchronized(mExecutionMutex) { // completion (Note: This is actually unnecessary)
      return mRunning;
      }
  }

  @Override
  public void run() {
    mRunning = true;
    startAnimation(mAnim);
  }

  // Called when mAnim finishes
  @Override
  public void onAnimationEnd(Animation animation) {
    synchronized(mExecutionMutex) { // completion
      mRunning = false;
      if(mRunnableB.isRunning() == false) {
        onBothRunnablesFinished();
      }
    }
  }
}
于 2011-07-13T03:13:47.167 回答