以下是我对自定义View
的一些代码的简化。动画有Runnable
,音频有Runnable
。 start()
函数启动动画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
会被调用两次。如果是这种情况,我该如何解决此问题?
答案 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互斥对象注入到两个可运行的对象中,并使用它来同步isRunning
和onCompletion
方法。实际上,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();
}
}
}
}