??之前有點忙,有一陣沒寫了;好,今天開始屬性動畫的第四部分,前面三節把屬性動畫的初始化的過程基本分析了一遍,今天就結合之前寫的內容,將屬性動畫是如何進行"start"的,完整的分析一遍。
??如果沒有看過之前的文章,建議看下之前的分析過程,以便可以更好的理解接下來的內容:
[Android屬性動畫源碼分析(一)]
[Android屬性動畫源碼分析(二)]
[Android屬性動畫源碼分析(三)]
animator.addListener(listener);//動畫監聽器
animator.setDuration(3000);//每次動畫運行時間
animator.setInterpolator(new LinearInterpolator());//插值器
animator.setRepeatCount(ValueAnimator.INFINITE);//重復次數
animator.start();//動畫開始
??前面四行的源碼很簡單,就不講了,從start開始講起,首先進入start的源碼:
//ObjectAnimator.java
@Override
public void start() {
AnimationHandler.getInstance().autoCancelBasedOn(this);
...
super.start();
}
??進入這個AnimationHandler看一下:
??官方文檔對它的解釋是:
//AnimatorHandler.java
/**
* This custom, static handler handles the timing pulse that is shared by all active
* ValueAnimators. This approach ensures that the setting of animation values will happen on the
* same thread that animations start on, and that all animations will share the same times for
* calculating their values, which makes synchronizing animations possible.
*
* The handler uses the Choreographer by default for doing periodic callbacks. A custom
* AnimationFrameCallbackProvider can be set on the handler to provide timing pulse that
* may be independent of UI frame update. This could be useful in testing.
*
* @hide
*/
??該handler主要是用于處理所有活動的屬性動畫共享的“時間脈沖”,這個時間脈沖是通常所理解的屬性動畫的從開始到結束每個時間段的“值”,它還保證了一個動畫的完整播放都是發生在同一個線程,同時,它還使用了一個關鍵的類“Choreographer(編舞者)”來處理周期的回調;另一個類AnimationFrameCallBackProvider用來給handler提供用于UI更新的時間脈沖。(這幾個類先記下,后面再表)
//AnimationHandler.java
public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();//這個handler的實例對象是一個ThreadLocal對象
public static AnimationHandler getInstance() {
if (sAnimatorHandler.get() == null) {//為每一個線程創建一個handler對象,這樣做是用于確保一個動畫的開始和結束都在同一個線程
sAnimatorHandler.set(new AnimationHandler());
}
return sAnimatorHandler.get();
}
//AnimationHandler.java
void autoCancelBasedOn(ObjectAnimator objectAnimator) {
for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {//當前回調還未進行添加,
//所以這個for循環不會走,如果走的話,代表停止之前正在播放的動畫,具體內容大家可以自行研究
AnimationFrameCallback cb = mAnimationCallbacks.get(i);
if (cb == null) {
continue;
}
if (objectAnimator.shouldAutoCancel(cb)) {
((Animator) mAnimationCallbacks.get(i)).cancel();
}
}
}
??在判斷完是否應該取消之前播放的動畫之后,我們就來到了super.start()方法:
//ValuesAnimator.java
public void start() {
start(false);//這里傳入了false,代表正序播放動畫
}
//ValuesAnimator.java
...
mReversing = playBackwards;
// Special case: reversing from seek-to-0 should act as if not seeked at all.
if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {//第一個參數就是false,所以不會走這里
...
}
mStarted = true;//設置當前狀態為start狀態
mPaused = false;
mRunning = false;
// Resets mLastFrameTime when start() is called, so that if the animation was running,
// calling start() would put the animation in the
// started-but-not-yet-reached-the-first-frame phase.
mLastFrameTime = 0;
AnimationHandler animationHandler = AnimationHandler.getInstance();//之前提到過的handler,這里進行了初始化(源碼在上面)
animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));//(1)將當前動畫對象添加到handler中,(第二個long的參數看初始化的值可知為0)
if (mStartDelay == 0 || mSeekFraction >= 0) {//由初始化代碼得知mStartDelay == 0,所以這里會走
// If there's no start delay, init the animation and notify start listeners right away
// to be consistent with the previous behavior. Otherwise, postpone this until the first
// frame after the start delay.
startAnimation();//(2)
if (mSeekFraction == -1) {//初始化值是-1,這里會走
// No seek, start at play time 0. Note that the reason we are not using fraction 0
// is because for animations with 0 duration, we want to be consistent with pre-N
// behavior: skip to the final value immediately.
setCurrentPlayTime(0);(3)
} else {
//本次不會走這里
setCurrentFraction(mSeekFraction);
}
}
??初始化的時候主要的工作:(1)將當前動畫給了AnimatonHandler;(2)調用了startAnimaton()方法;(3)調用了setCurrentPlayTime()方法,并且傳入了參數0,接下來按順序分析下調用的這三個方法:
(1)
//AnimatonHandler.java
/**
* Register to get a callback on the next frame after the delay.
*/
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {//這里的size是0,所以這里會走
getProvider().postFrameCallback(mFrameCallback);
}
if (!mAnimationCallbacks.contains(callback)) {當前的list還無數據,所以這里會進入
mAnimationCallbacks.add(callback);//這里添加的是ObjectAnimator對象
}
if (delay > 0) {//當前delay是0
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
??這個mFrameCallback是誰呢,我們看下它的定義:
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
??是一個Choreographer#FrameCallBack類型,這個mFrameCallback是怎么運作的呢,在分析完后面的內容在繼續分析,這里先標記下。
??我們在看下getProvider().postFrameCallBack(mFrameCallback);的內容
//AnimatonHandler.java
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
//MyFrameCallbackProvider.java
/**
* Default provider of timing pulse that uses Choreographer for frame callbacks.
*/
private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
@Override
public void postCommitCallback(Runnable runnable) {
mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
}
@Override
public long getFrameTime() {
return mChoreographer.getFrameTime();
}
@Override
public long getFrameDelay() {
return Choreographer.getFrameDelay();
}
@Override
public void setFrameDelay(long delay) {
Choreographer.setFrameDelay(delay);
}
}
??由上面可以看到,MyFrameCallBackProvider相當于Choregrapher的代理類,所以接下來這塊的分析我們直接進入Choregrapher類去查看,關于這個類的相關機制,鑒于篇幅有限,我們就踩在巨人的肩膀上,可以參考這篇文章:Android消息機制Looper與VSync的傳播 ,我們只看相關動畫的部分:
//Choreographer.java
public void postFrameCallback(FrameCallback callback) {
postFrameCallbackDelayed(callback, 0);
}
??上邊的方法傳入了回調對象,延遲時間為0,進入postFrameCallbackDelayed:
//Choreographer.java
public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
...\\省略一些判斷過程
}
postCallbackDelayedInternal(CALLBACK_ANIMATION,
callback, FRAME_CALLBACK_TOKEN, delayMillis);
}
??在上邊的方法里,最后會調用postCallBackDelayedInternal方法進行最終處理,callBacktype是CALLBACK_ANIMATION,action就是回調對象,token是FRAME_CALLBACK_TOKEN,delayMillis是0:
//Choreographer.java
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
...
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;//這里delayMillis = 0
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);//回調存入了CALLBACK_ANIMATION隊列中
if (dueTime <= now) {
scheduleFrameLocked(now);//由于dueTime == now,這里將被執行,進入垂直同步過程
} else {
...
}
}
}
??由上面的代碼可知,我們將回調對象最終存入了mCallBackQueues[CALLBACK_ANIMATION]中(這是一個存放各個類型的數組,每個數組元素是一個CallbackQueue用于存放不同類型的回調:
//Choreographer.java
private final CallbackQueue[] mCallbackQueues;
??由之前的代碼分析可知,我們播放的動畫是CALLBACK_ANIMATION類型,addCallbackLocked方法我們將在下面進行分析)然后編舞者將會執行一次垂直同步(具體參見相關文章,這里不展開),一系列的過程后,會調用Choregrapher中 CallBackRecord對象的run方法,最終進入doFrame方法:
//Choreographer.java
void doFrame(long frameTimeNanos, int frame) {
...
try {
...
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
...
}
(補充,根據VSYNC機制,每次接收到垂直同步信號時,都會經過一系列的分發執行到doFrame方法)
??這里只列出一些關鍵部分,通過這部分可以看出,doFrame方法調用了doCallBacks方法用來處理不同類型的回調,由于不涉及其他三種類型,只看傳入的類型是Choreographer.CALLBACK_ANIMATION,doCallBacks是如何處理的
//Choreographer.java
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);//取出回調方法
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
...
try {
...
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
c.run(frameTimeNanos);//執行回調
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {//這里recycle了相關類型的回調
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
...
}
}
??上邊的代碼主要做了兩件事,取出相應類型的“回調隊列”(其實是個鏈表),執行隊列中每個回調的run方法;
先說第一件事,前面說過要分析一下addCallbackLocked方法,正好在這里和extractDueCallbacksLocked一起分析:
這兩個方法都是CallbackQueue里的方法:
mCallbackQueues[CALLBACK_ANIMATION].addCallbackLocked(now, callback, token);//這里只是列出之前的調用及傳參
//Choreographer#CallbackQueue
public void addCallbackLocked(long dueTime, Object action, Object token) {
CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
CallbackRecord entry = mHead;
if (entry == null) {
mHead = callback;
return;
}
if (dueTime < entry.dueTime) {
callback.next = entry;
mHead = callback;
return;
}
while (entry.next != null) {
if (dueTime < entry.next.dueTime) {
callback.next = entry.next;
break;
}
entry = entry.next;
}
entry.next = callback;
}
??上邊的代碼就是按照dueTime的順序將通過obtainCallbackLocked生成的CallbackRecord放到鏈表的合適位置進行存儲(CallbackRecord就是一個鏈表的存儲結構);
//Choreographer#CallbackQueue
private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
CallbackRecord callback = mCallbackPool;
if (callback == null) {
callback = new CallbackRecord();
} else {
mCallbackPool = callback.next;
callback.next = null;
}
callback.dueTime = dueTime;
callback.action = action;//注意,動畫本身的callback放到了這里
callback.token = token;
return callback;
}
??上邊就是生成一個CallbackRecord的過程,動畫播放的callback放到了CallbackRecord的action中。
??接下來看看取出的時候是怎么做的:
//Choreographer#CallbackQueue
public CallbackRecord extractDueCallbacksLocked(long now) {
CallbackRecord callbacks = mHead;
if (callbacks == null || callbacks.dueTime > now) {
return null;
}
CallbackRecord last = callbacks;
CallbackRecord next = last.next;
while (next != null) {
if (next.dueTime > now) {
last.next = null;
break;
}
last = next;
next = next.next;
}
mHead = next;
return callbacks;
}
??總體來說,就是將鏈表頭部返回,并且移除了當前時間之后的元素。
??上邊一系列方法看完以后就拿到了callbacks,通過for循環對這個鏈表遍歷執行每個CallbackRecord的run方法:
//Choreographer#CallbackRecord
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
??由前邊的代碼可知,這里的token就是FRAME_CALLBACK_TOKEN,所以將執行doFrame方法,還記得這個action是誰嗎,沒錯,就是前面說要在后面分析的mFrameCallback!
??到這里,getProvider().postFrameCallback(mFrameCallback);的過程就分析完了,總結起來就是,我們的這次animation創建了一個AnimationFrameCallbackProvider,在AnimationHander里添加了一個FrameCallback類型的回調(如果之前沒有的話),這個FrameCallback將通過provider發送給Choregrapher(編舞者),被編舞者封裝為CallbackRecord類型的內容,在一次垂直同步信號分發時,這個callbackRecord將會被調用,并最終調用FrameCallback的doFrame方法,同時,本次animation也添加到了AnimationHander的回調列表中,接下來的一篇文章我們將開始分析mFrameCallback的doFrame方法。