屬性動畫的啟動我們是通過如下來完成的:
objectAnimator.start();//動畫開始時從start方法開始的
start()
核心代碼如下:
AnimationHandler.getInstance().autoCancelBasedOn(this);
super.start();
start()
方法主要做了兩件事,一個是檢測如果動畫已經執行,則停止動畫;另一方面調用了父類的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實現了AnimationFrameCallback接口
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
流程走到這里,需要看兩個方法:
- getAnimationHandler()
看下getAnimationHandler()
這個方法:
public AnimationHandler getAnimationHandler() {
return AnimationHandler.getInstance();//getInstance()這個方法
}
AnimationHandler
不是Handler,而是AnimationHandler用ThreadLocal保證每個線程只有一個實例。做到線程中單例,“getInstance()”方法以及實現如下:
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
這個方法,通過不斷的調用跳轉,我們來到了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) {
//沒有延遲,直接開始調度
scheduleFrameLocked(now);
} else {
//有延遲,就通過handler延時發送一個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) {//為動畫和繪圖啟動/禁用垂直同步信號
//如果是在主線程就直接調度,否則就發送一個消息到主線程
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
}
然后看下這個方法scheduleVsyncLocked
,通過不斷的跳轉,我們可以看到在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);
總結:start
方法中檢測如果動畫已經執行,則停止動畫,并且限定了動畫只能在主線程中運行,動畫如果在主線程中運行,那么將會判斷有沒有啟動延遲,如果沒有就立即執行動畫,通過AnimationHandler
用ThreadLocal
保證每個線程只有一個實例。做到線程中單例。執行動畫后,會為動畫和繪圖啟動垂直同步信號,通過向native
曾注冊成為觀察者,用來接收屏幕刷新信號。