android startanimation 回调,ScheduledThreadPoolExecutor执行莫名停止问题Android几个动画回调运行线程...
本文記錄兩個問題:
ScheduleThreadPoolExecutor莫名停止執行。Animation和Animator兩個動畫回調監聽 運行在哪個線程。
一:ScheduleThreadPoolExecutor問題:
ScheduledThreadPoolExecutor中scheduleWithFixedDelay(command, initialDelay, delay, unit)這個方法。我們會實現command這個Runnable參數。
問題:
當我們實現run()方法時,如果run()方法內運行時報錯,那么ScheduleThreadPoolExecutor會自動停止,并且app不會崩潰,logcat也不會打印錯誤日志。。。
解決方法:
在api中也介紹了,如果希望executor繼續運行下去,那么就必須將報錯try catch掉。否則報錯線程池將停止繼續運行。
二:Animation和Animator兩個動畫回調監聽 運行在哪個線程:
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傳遞給mListenerHanlder去處理了。那么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。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的android startanimation 回调,ScheduledThreadPoolExecutor执行莫名停止问题Android几个动画回调运行线程...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 咪咕视频好用吗(上的咪咕视频)
- 下一篇: 电脑系统设置闹钟详细步骤