ScheduledThreadPoolExecutor実行莫名停止問題&Androidいくつかのアニメーションコールバック実行スレッド
5456 ワード
この文書には、次の2つの問題が記載されています. ScheduleThreadPoolExecutorはなぜか実行を停止した. AnimationとAnimatorの2つのアニメーションコールバックは、どのスレッドで実行されているかをリスニングします.
一:ScheduleThreadPoolExecutor問題:
ScheduledThreadPoolExecutorにおけるscheduleWithFixedDelay(command,initialDelay,delay,unit)という方法.commandというRunnableパラメータを実装します.
質問:
run()メソッドを実装すると、run()メソッド内でタイムズエラーが実行されると、ScheduleThreadPoolExecutorは自動的に停止し、appはクラッシュせず、logcatもエラーログを印刷しません.
解決方法:
apiでも紹介されていますが、executorを継続したい場合は、try catchのエラーを報告しなければなりません.エラー・スレッド・プールが実行を停止します.
2:AnimationとAnimatorの2つのアニメーションコールバックリスニングが実行されるスレッド:
setAnimationListener(new ...{
onAnimationStart()
onAnimationRepeat()
onAnimationEnd()
})
1.Animation:Viewアニメーション
まず、このコールバック呼び出しの場所を見つけます.Animationクラスで、ソースコード:
コールバックメソッドがRunnableに組み込まれているのが見えますが、理屈を言えばhandlerで処理されます.
では、mOnStartを探します.のこれらのパラメータはどこで呼び出されましたか.
はい、RunnableをmListener Hanlderに渡して処理しました.ではmListenerHandlerというhandlerはどこで与えられたのでしょうか.ああ..上の方法の最後に
最後に、Viewクラスで次のコードが見つかりました.
A Handler supplied by a view's {@link android.view.ViewRootImpl}. This handler can be used to pump events in the UI events queue.
これはAttachInfoクラスのmHandlerのコメントです.管理UIのhandlerであることがわかります.それはメインスレッドでコールバックメソッドを実行したに違いない.
結論:Animationコールバック方法はメインスレッドにあるに違いない.
2.Animator:属性アニメーションValueAnimatorなど
同様に、listenerがソースコードのどこで呼び出されたかを見てみましょう.
一:ScheduleThreadPoolExecutor問題:
ScheduledThreadPoolExecutorにおけるscheduleWithFixedDelay(command,initialDelay,delay,unit)という方法.commandというRunnableパラメータを実装します.
質問:
run()メソッドを実装すると、run()メソッド内でタイムズエラーが実行されると、ScheduleThreadPoolExecutorは自動的に停止し、appはクラッシュせず、logcatもエラーログを印刷しません.
解決方法:
apiでも紹介されていますが、executorを継続したい場合は、try catchのエラーを報告しなければなりません.エラー・スレッド・プールが実行を停止します.
2:AnimationとAnimatorの2つのアニメーションコールバックリスニングが実行されるスレッド:
setAnimationListener(new ...{
onAnimationStart()
onAnimationRepeat()
onAnimationEnd()
})
1.Animation:Viewアニメーション
まず、このコールバック呼び出しの場所を見つけます.Animationクラスで、ソースコード:
/**
* Sets the handler used to invoke listeners.
*
* @hide
*/
public void setListenerHandler(Handler handler) {
if (mListenerHandler == null) {
mOnStart = new Runnable() {
public void run() {
if (mListener != null) {
mListener.onAnimationStart(Animation.this);
}
}
};
mOnRepeat = new Runnable() {
public void run() {
if (mListener != null) {
mListener.onAnimationRepeat(Animation.this);
}
}
};
mOnEnd = new Runnable() {
public void run() {
if (mListener != null) {
mListener.onAnimationEnd(Animation.this);
}
}
};
}
mListenerHandler = handler;
}
コールバックメソッドがRunnableに組み込まれているのが見えますが、理屈を言えばhandlerで処理されます.
では、mOnStartを探します.のこれらのパラメータはどこで呼び出されましたか.
private void fireAnimationStart() {
if (mListener != null) {
if (mListenerHandler == null) mListener.onAnimationStart(this);
else mListenerHandler.postAtFrontOfQueue(mOnStart);
}
}
はい、RunnableをmListener Hanlderに渡して処理しました.ではmListenerHandlerというhandlerはどこで与えられたのでしょうか.ああ..上の方法の最後に
mListenerHandler = handler;
最後に、Viewクラスで次のコードが見つかりました.
if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
A Handler supplied by a view's {@link android.view.ViewRootImpl}. This handler can be used to pump events in the UI events queue.
これはAttachInfoクラスのmHandlerのコメントです.管理UIのhandlerであることがわかります.それはメインスレッドでコールバックメソッドを実行したに違いない.
結論:Animationコールバック方法はメインスレッドにあるに違いない.
2.Animator:属性アニメーションValueAnimatorなど
同様に、listenerがソースコードのどこで呼び出されたかを見てみましょう.
private void notifyStartListeners() {
if (mListeners != null && !mStartListenersCalled) {
ArrayList tmpListeners =
(ArrayList) mListeners.clone();
int numListeners = tmpListeners.size();
for (int i = 0; i < numListeners; ++i) {
tmpListeners.get(i).onAnimationStart(this);
}
}
mStartListenersCalled = true;
}
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
...
if (mStartDelay == 0) {
...
notifyStartListeners();
}
animationHandler.start();
}
Animatorのstart()は、上のstart(boolean)メソッドを呼び出し、notifyStartListeners()メソッドを呼び出します.このように見ると、Animatorという意味です.start()メソッドはどのスレッドで実行され、コールバックはどのスレッドで実行されますか.後でテストしましょう.次のコードに注意してください.AndroidRuntimeException("Animators may only be run on Looper threads");
Animatorはサブスレッドで実行できるように見えますが、このスレッドにはlooperが必要です!はい、コードテストをしてください.final ValueAnimator va = ObjectAnimator.ofFloat(0, 1);
va.setDuration(5000);
va.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.e("TAG", "onAnimationUpdate"
+ Thread.currentThread().getName());
// start
}
});
va.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Log.e("TAG", "onAnimationStart"
+ Thread.currentThread().getName());
}
@Override
public void onAnimationRepeat(Animator animation) {
Log.e("TAG", "onAnimationRepeat"
+ Thread.currentThread().getName());
}
@Override
public void onAnimationEnd(Animator animation) {
Log.e("TAG", "onAnimationEnd"
+ Thread.currentThread().getName());
}
@Override
public void onAnimationCancel(Animator animation) {
Log.e("TAG", "onAnimationCancel"
+ Thread.currentThread().getName());
}
});
//va.start();
new Thread("hah") {public void run() {Looper.prepare();va.start();Looper.loop();};}.start();
のコードテストの 、やはりstart()がプライマリスレッドで び されると、コールバックメソッドはすべてプライマリスレッドになります.「hah」というサブスレッドで び されると、コールバックメソッドはすべて「hah」サブスレッドにあります.
:Animatorのstart()メソッドがどのスレッドで び され、コールバックがどのスレッドにあるか. :サブスレッドにはlooperが です.