屬性動畫的啟動我們是通過如下來完成的:
objectAnimator.start();//動畫開始時從start方法開始的
start()核心代碼如下:
AnimationHandler.getInstance().autoCancelBasedOn(this);
super.start();
start()方法主要做了兩件事,一個是檢測如果動畫已經(jīng)執(zhí)行,則停止動畫;另一方面調(diào)用了父類的start()方法。
ObjectAnimator的父類是ValueAnimator,它的start()方法如下:
start(false);
我們接著看下ValueAnimator的這個方法,核心代碼如下:
//開啟動畫的線程要有Looper對象=》動畫只能在主線程中運行
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
startAnimation(); //如果沒有啟動延遲,就立即啟動動畫
if (mSeekFraction == -1) {
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
這里主要看addAnimationCallback(0);
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
//添加一個AnimationFrameCallback,ValueAnimator實現(xiàn)了AnimationFrameCallback接口
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
流程走到這里,需要看兩個方法:
- getAnimationHandler()
看下getAnimationHandler()這個方法:
public AnimationHandler getAnimationHandler() {
return AnimationHandler.getInstance();//getInstance()這個方法
}
AnimationHandler不是Handler,而是AnimationHandler用ThreadLocal保證每個線程只有一個實例。做到線程中單例,“getInstance()”方法以及實現(xiàn)如下:
public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
private boolean mListDirty = false;
public static AnimationHandler getInstance() {
if (sAnimatorHandler.get() == null) {
sAnimatorHandler.set(new AnimationHandler());
}
return sAnimatorHandler.get();
}
- addAnimationFrameCallback
addAnimationFrameCallback的核心代碼:
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
}
AnimationFrameCallback是ValueAnimator的父類,getProvider()返回的是MyFrameCallbackProvider,我們來看下postFrameCallback這個方法,通過不斷的調(diào)用跳轉(zhuǎn),我們來到了Choreographer的postCallbackDelayedInternal這個方法:
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {//這個action就是callback
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
//沒有延遲,直接開始調(diào)度
scheduleFrameLocked(now);
} else {
//有延遲,就通過handler延時發(fā)送一個message
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
看下scheduleFrameLocked(now);這個方法:,核心代碼如下:
if (USE_VSYNC) {//為動畫和繪圖啟動/禁用垂直同步信號
//如果是在主線程就直接調(diào)度,否則就發(fā)送一個消息到主線程
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
}
然后看下這個方法scheduleVsyncLocked,通過不斷的跳轉(zhuǎn),我們可以看到在DisplayEventReceiver這個類中的scheduleVsync方法如下:
public void scheduleVsync() {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
+ "receiver has already been disposed.");
} else {
nativeScheduleVsync(mReceiverPtr);
}
}
nativeScheduleVsync方法其實是一個native方法,這個方法其實是向native層注冊成為觀察者,用來接收屏幕刷新信號。
private static native void nativeScheduleVsync(long receiverPtr);
總結(jié):start方法中檢測如果動畫已經(jīng)執(zhí)行,則停止動畫,并且限定了動畫只能在主線程中運行,動畫如果在主線程中運行,那么將會判斷有沒有啟動延遲,如果沒有就立即執(zhí)行動畫,通過AnimationHandler用ThreadLocal保證每個線程只有一個實例。做到線程中單例。執(zhí)行動畫后,會為動畫和繪圖啟動垂直同步信號,通過向native曾注冊成為觀察者,用來接收屏幕刷新信號。