同一个线程上的两个Runnable同时结束。冲突可能吗?

时间:2011-07-13 02:34:16

标签: java android callback runnable

以下是我对自定义View的一些代码的简化。动画有Runnable,音频有Runnablestart()函数启动动画runnable和audio runnable。每个runnable在完成时实现一个带回调的接口。

我需要知道两者何时完成,所以我可以致电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();
      }
    }
  }
}

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

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

3 个答案:

答案 0 :(得分: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会为你做多线程。

百里

答案 1 :(得分:1)

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

并使用

完成运行
if(atomicInt.decrementAndGet()==0)onBothRunnablesFinished();

答案 2 :(得分: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();
      }
    }
  }
}