0

以下は、私がカスタム用に持っているいくつかのコードの簡略化ですViewRunnableアニメーション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();
      }
    }
  }
}

関心のあるいくつかの領域にコメントを付けました。オーディオとアニメーションのランナブルが同時に終了するとどうなりますか?より具体的には、一方の実行可能ファイルのコールバックは、上記のコメントされた場所でもう一方のコールバックを中断できますか?これは可能ですか?

onBothRunnablesFinishedそれなら二度呼ばれるので、私はそうしないことを望みます。この場合、どうすればこの問題を解決できますか?

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();
    }
}

私を信じてください。このコードは機能し、ずっときれいです。Androidがマルチスレッドを実行するので、Runnablesの使用を考えないでください。

バリー

于 2011-07-13T04:17:18.680 に答える
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 に答える
1

2に初期化されたAtomicIntegerを使用できます

で実行を終了します

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