主目錄見:Android高級(jí)進(jìn)階知識(shí)(這是總目錄索引)
?昨天已經(jīng)簡單講了下使用烤礁,今天又是源碼分析環(huán)節(jié)晌涕,之前看別人分析的動(dòng)畫源碼都是舊版的,因?yàn)镃horeographer在android 4.1之后引入的,所以在之前的分析中都看不到這個(gè)身影饥侵。今天我們就來揭開動(dòng)畫的神秘面紗哈。
一.目標(biāo)
?之所以分析這篇衣屏,也是自己的一個(gè)源碼癖躏升,總覺得沒分析源碼有點(diǎn)不完整,還有大家可以通過這個(gè)源碼更加了解動(dòng)畫的過程怎么走狼忱,所以我們今天目標(biāo):
1.了解動(dòng)畫的運(yùn)動(dòng)過程膨疏;
2.隆重了解Choreographer這個(gè)類,翻譯為編舞者藕赞,控制節(jié)奏有木有成肘。
二.源碼分析
1.ObjectAnimator ofInt()
我們都知道,我們前面一篇《屬性動(dòng)畫的基礎(chǔ)使用方法》已經(jīng)講過基本使用了斧蜕,那么我們從使用出發(fā)双霍,首先從ObjectAnimator的用法開始看,我們挑一個(gè)簡單點(diǎn)的方法進(jìn)入:
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setIntValues(values);
return anim;
}
這個(gè)方法就幾句話批销,老套路洒闸,一句一句來看,首先我們看到第一句實(shí)例化了一個(gè)ObjectAnimator對象均芽,那我們進(jìn)去看看這個(gè)構(gòu)造函數(shù)做了啥:
private ObjectAnimator(Object target, String propertyName) {
setTarget(target);
setPropertyName(propertyName);
}
我們看這里設(shè)置了Target即視圖丘逸,還有就是屬性名,我們這里簡單看下干了啥掀宋,這兩個(gè)方法深纲,首先看下第一個(gè)方法:
@Override
public void setTarget(@Nullable Object target) {
final Object oldTarget = getTarget();
if (oldTarget != target) {
if (isStarted()) {
cancel();
}
mTarget = target == null ? null : new WeakReference<Object>(target);
// New target should cause re-initialization prior to starting
mInitialized = false;
}
}
這個(gè)方法很簡單,其實(shí)就是先獲取之前是否設(shè)置過Target了劲妙,設(shè)置過就不設(shè)置了湃鹊,如果沒有就判斷下這個(gè)動(dòng)畫是否開始了,開始了就取消掉镣奋,然后將這個(gè)target重新設(shè)置一下币呵。我們繼續(xù)看屬性怎么設(shè)置:
public void setPropertyName(@NonNull String propertyName) {
// mValues could be null if this is being constructed piecemeal. Just record the
// propertyName to be used later when setValues() is called if so.
if (mValues != null) {
PropertyValuesHolder valuesHolder = mValues[0];
String oldName = valuesHolder.getPropertyName();
valuesHolder.setPropertyName(propertyName);
mValuesMap.remove(oldName);
mValuesMap.put(propertyName, valuesHolder);
}
mPropertyName = propertyName;
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
這個(gè)方法首先判斷mValues即PropertyValuesHolder[]數(shù)組變量是否已經(jīng)設(shè)置過了,沒有設(shè)置過直接設(shè)置屬性名侨颈,設(shè)置過了則進(jìn)行關(guān)聯(lián)屬性名和PropertyValuesHolder對象余赢。等會(huì)就知道PropertyValuesHolder干啥的了芯义。看完第一句我們來看第二句 anim.setIntValues(values)了:
@Override
public void setIntValues(int... values) {
if (mValues == null || mValues.length == 0) {
// No values yet - this animator is being constructed piecemeal. Init the values with
// whatever the current propertyName is
if (mProperty != null) {
setValues(PropertyValuesHolder.ofInt(mProperty, values));
} else {
setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
}
} else {
super.setIntValues(values);
}
}
我們知道妻柒,這邊的mProperty 我們還沒有在哪里賦值過扛拨,這個(gè)地方肯定是走的else,所以我們來看看else里面做了啥蛤奢,我們首先看下PropertyValuesHolder.ofInt()干了啥:
public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values) {
return new IntPropertyValuesHolder(property, values);
}
我們看到這個(gè)里面主要實(shí)例化了IntPropertyValuesHolder鬼癣,所以我們看下:
public IntPropertyValuesHolder(String propertyName, int... values) {
super(propertyName);
setIntValues(values);
}
第一句很簡單我們就不看了,就是設(shè)置propertyName啤贩,我們直接看第二句:
@Override
public void setIntValues(int... values) {
super.setIntValues(values);
mIntKeyframes = (Keyframes.IntKeyframes) mKeyframes;
}
第一句調(diào)用了父類的setIntValues方法待秃,我們直接來看:
public void setIntValues(int... values) {
mValueType = int.class;
mKeyframes = KeyframeSet.ofInt(values);
}
第一句是設(shè)置了PropertyValuesHolder值類型為int因?yàn)槲覀冞@里調(diào)用的是ofInt()方法,然后我們看下KeyframeSet.ofInt()怎么走的:
public static KeyframeSet ofInt(int... values) {
int numKeyframes = values.length;
IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
if (numKeyframes == 1) {
//如果只有一個(gè)值痹屹,我們就把這個(gè)值當(dāng)做運(yùn)動(dòng)的最終值
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
} else {
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
for (int i = 1; i < numKeyframes; ++i) {
//將每一幀都設(shè)置進(jìn)IntKeyframe 數(shù)組中
keyframes[i] =
(IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
}
}
return new IntKeyframeSet(keyframes);
}
終于到了可以稍微講下的方法了章郁,不然總是簡單地跳來跳去會(huì)被看的人打死。第一個(gè)numKeyframes == 1說明傳進(jìn)來ofInt的values就一個(gè)志衍,那么我們就當(dāng)做設(shè)置進(jìn)來的值為運(yùn)動(dòng)的最終值暖庄。如果設(shè)置進(jìn)來有幾個(gè)值那么我們就設(shè)置為幾幀放進(jìn)IntKeyframe 數(shù)組然后最后賦值給IntKeyframeSet中的
List<Keyframe> mKeyframes中去。到這里我們的PropertyValuesHolder中的KeyframeSet賦值完了楼肪,KeyframeSet中又包含了Keyframe(關(guān)鍵幀)的數(shù)組培廓,也就是說我們設(shè)置進(jìn)來的values最后都轉(zhuǎn)化為keyframe的數(shù)組。然后我們回去看下setValues()方法是干了什么:
public void setValues(PropertyValuesHolder... values) {
int numValues = values.length;
mValues = values;
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
for (int i = 0; i < numValues; ++i) {
PropertyValuesHolder valuesHolder = values[i];
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
因?yàn)槲覀働ropertyValuesHolder里面屬性已經(jīng)賦值完成了春叫,現(xiàn)在我們就開始設(shè)置這個(gè)對象值肩钠。上面這段代碼也很簡單,就是將視圖的屬性名和PropertyValuesHolder對象關(guān)聯(lián)放進(jìn)mValuesMap中來即可暂殖。
2.ObjectAnimator start()
在上面除了TypeEvaluator(估值器)和TimeInterpolator(插值器)之外价匠,值是都設(shè)置了,這兩個(gè)我們等會(huì)可以看下呛每,其實(shí)就是設(shè)置進(jìn)去而已踩窖,現(xiàn)在因?yàn)槲覀兊年P(guān)鍵幀都設(shè)置完畢了,我們就可以開始運(yùn)動(dòng)了:
@Override
public void start() {
//如果設(shè)置了自動(dòng)取消動(dòng)畫晨横,則遍歷調(diào)用取消
AnimationHandler.getInstance().autoCancelBasedOn(this);
if (DBG) {
Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
for (int i = 0; i < mValues.length; ++i) {
PropertyValuesHolder pvh = mValues[i];
Log.d(LOG_TAG, " Values[" + i + "]: " +
pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
pvh.mKeyframes.getValue(1));
}
}
super.start();
}
這個(gè)方法就兩句代碼有用洋腮,因?yàn)榕袛嗬锩嬷R(shí)打印而已,第一句如注釋所說手形,我們看到下面super.start()方法啥供,我們知道ObjectAnimator是ValueAnimator的子類,所以我們看ValueAnimator的start()方法:
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
//這個(gè)標(biāo)志是說明是否循環(huán)動(dòng)畫的
mReversing = playBackwards;
// Special case: reversing from seek-to-0 should act as if not seeked at all.
if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
if (mRepeatCount == INFINITE) {
//這是無限循環(huán)動(dòng)畫計(jì)算fraction的方式叁幢,用到了Math.floor(向下取整數(shù)),也就是說mSeekFraction 為1的時(shí)候計(jì)算下來又變?yōu)?坪稽,從頭開始循環(huán)
// Calculate the fraction of the current iteration.
float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
mSeekFraction = 1 - fraction;
} else {
//有限次循環(huán)動(dòng)畫計(jì)算fraction方式
mSeekFraction = 1 + mRepeatCount - mSeekFraction;
}
}
//這幾個(gè)就是動(dòng)畫的執(zhí)行狀態(tài)的
mStarted = true;
mPaused = false;
mRunning = false;
mAnimationEndRequested = 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;
//#下面代碼都非常重要會(huì)依次分析
AnimationHandler animationHandler = AnimationHandler.getInstance();
animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
if (mStartDelay == 0 || mSeekFraction >= 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();
if (mSeekFraction == -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);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
這里就是我們啟動(dòng)動(dòng)畫的關(guān)鍵代碼了曼玩,我們先看AnimationHandler的addAnimationFrameCallback方法鳞骤,傳進(jìn)去的參數(shù)是本身this,也就是ObjectAnimator對象同時(shí)這個(gè)類實(shí)現(xiàn)了AnimationFrameCallback接口黍判,我們記住了豫尽,因?yàn)榈葧?huì)會(huì)回調(diào),我們先跟進(jìn)這個(gè)方法里面吧:
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
我們看到第一個(gè)判斷mAnimationCallbacks明顯就是空顷帖,因?yàn)槲覀冞€沒給他設(shè)置呢美旧,所以我們程序會(huì)執(zhí)行g(shù)etProvider().postFrameCallback(mFrameCallback)這一句代碼,然后我們會(huì)把傳進(jìn)來的參數(shù)callback添加進(jìn)mAnimationCallbacks這個(gè)List中贬墩,postFrameCallback這句代碼其實(shí)非常關(guān)鍵榴嗅,我們首先來看getProvider()方法:
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
我們看到getProvider就是獲取了MyFrameCallbackProvider對象,那么我們跟進(jìn)這個(gè)對象的postFrameCallback()方法陶舞,記住這個(gè)方法里面的參數(shù)是
mFrameCallback不是我們傳進(jìn)來的參數(shù)嗽测,不要看錯(cuò)了,我最開始就看錯(cuò)了肿孵,這個(gè)CallBack是什么呢:
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
因?yàn)檫@個(gè)是回調(diào)唠粥,所以等會(huì)才會(huì)調(diào)用,我們這個(gè)地方就留意一下停做,我們現(xiàn)在進(jìn)入postFrameCallback方法里面:
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
這個(gè)地方我們終于看到我們的主角了mChoreographer(編舞者的對象)晤愧,我們迫不及待趕緊往Choreographer類里面的postFrameCallback跟進(jìn),最終會(huì)到下面這個(gè)方法 postCallbackDelayedInternal(CALLBACK_ANIMATION,callback, FRAME_CALLBACK_TOKEN, delayMillis)里面:
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
...............
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
我們注意傳進(jìn)來的參數(shù)第一個(gè)callbackType為CALLBACK_ANIMATION蛉腌,這個(gè)后面會(huì)用到官份,其實(shí)這個(gè)值是固定的為1,也就是說后面這個(gè)mCallbackQueues[callbackType]這個(gè)其實(shí)是往這個(gè)數(shù)組的這個(gè)位置(這個(gè)位置連接著一個(gè)單鏈表結(jié)構(gòu))加入CallbackRecord眉抬,我們看下這個(gè)addCallbackLocked干了些啥:
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;
}
這個(gè)方法就是很典型的鏈表的一些操作贯吓,我們先看第一個(gè)判斷,如果是entry為空蜀变,也就是頭結(jié)點(diǎn)為空悄谐,那么我們就把新創(chuàng)建的作為頭結(jié)點(diǎn)。如果頭結(jié)點(diǎn)不為空的話库北,我們看第二個(gè)判斷我們判斷如果開始動(dòng)畫時(shí)間早于頭結(jié)點(diǎn)則采用頭部插入的方法把CallbackRecord 插入鏈表爬舰。不然我們就循環(huán)這個(gè)鏈表,一個(gè)一個(gè)比較動(dòng)畫開始時(shí)間寒瓦,然后在合適位置插入情屹。好啦添加完鏈表,我們回去前面代碼if (dueTime <= now) 杂腰,因?yàn)槲覀兊膁elayMillis我們沒有傳值垃你,所以判斷肯定是小于等于的,所以我們會(huì)走到scheduleFrameLocked方法:
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
// If running on the Looper thread, then schedule the vsync immediately,
// otherwise post a message to schedule the vsync from the UI thread
// as soon as possible.
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
我們看到會(huì)判斷if(USE_VSYNC),我們知道用的就是VSYNC(垂直同步信號(hào)),所以我們代碼會(huì)走進(jìn)來惜颇,我們看到 if (isRunningOnLooperThreadLocked()) 這句是判斷是否當(dāng)前的looper和我所在的looper一致皆刺,一般情況下是成立的,所以我們會(huì)調(diào)用scheduleVsyncLocked()方法:
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
我們看下mDisplayEventReceiver這個(gè)對象是FrameDisplayEventReceiver凌摄,所以我們要跟進(jìn)到這個(gè)類的scheduleVsync()方法羡蛾,懵逼了,發(fā)現(xiàn)這個(gè)類并沒有這個(gè)方法锨亏,那怎么辦痴怨,在父類嘛,最后找到了:
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);
}
}
淚流滿面器予,這個(gè)nativeScheduleVsync方法是native方法浪藻,線索頓時(shí)斷了有木有,其實(shí)到這里只能去看底層的源碼劣摇,或者你看到這個(gè)方法下面也會(huì)有驚喜的發(fā)現(xiàn):
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
onVsync(timestampNanos, builtInDisplayId, frame);
}
看到英文的注釋了沒有珠移,不要太清晰,我們這里不分析底層c++的源碼了末融,我們直接給出結(jié)論钧惧,會(huì)調(diào)用這個(gè)方法。然后我們看到onVsync()方法勾习,這個(gè)方法在子類FrameDisplayEventReceiver中有實(shí)現(xiàn)浓瞪,我們來看做了啥:
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
scheduleVsync();
return;
}
long now = System.nanoTime();
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
} else {
mHavePendingVsync = true;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
我們看到最后是發(fā)了一個(gè)消息,這個(gè)消息的obtain方法的第二個(gè)參數(shù)是一個(gè)callback巧婶,也就是說這個(gè)消息會(huì)執(zhí)行這個(gè)回調(diào)(如果熟悉消息機(jī)制應(yīng)該知道)乾颁,這個(gè)回調(diào)會(huì)調(diào)用到這個(gè)類的run方法,所以我們看到這個(gè)類的run()方法:
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
這個(gè)方法很簡單艺栈,就是調(diào)用doFrame方法英岭,所以我們直接跟進(jìn)去,大家不要亂湿右,腦子要清醒诅妹,這里我提醒你,這個(gè)方法很重要R闳恕?越啤!:
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
......
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= mFrameIntervalNanos) {
//這個(gè)判斷是判斷是否有跳幀情況丈莺,我們知道我們的mFrameIntervalNanos系統(tǒng)建議是16ms一幀划煮,如果大于這個(gè)值則會(huì)出現(xiàn)丟幀的情況,這也是為什么頁面會(huì)卡頓的原因
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! "
+ "The application may be doing too much work on its main thread.");
}
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ "which is more than the frame interval of "
+ (mFrameIntervalNanos * 0.000001f) + " ms! "
+ "Skipping " + skippedFrames + " frames and setting frame "
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
frameTimeNanos = startNanos - lastFrameOffset;
}
//因?yàn)橹俺霈F(xiàn)了丟幀的情況缔俄,所以這個(gè)時(shí)間好像還是之前的時(shí)間弛秋,所以直接等待下一幀
if (frameTimeNanos < mLastFrameTimeNanos) {
if (DEBUG_JANK) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ "previously skipped frame. Waiting for next vsync.");
}
scheduleVsyncLocked();
return;
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
//我們下面打算分析這個(gè)地方
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);
}
............
}
前面部分我們已經(jīng)注釋解釋了一下器躏,我們現(xiàn)在分析幾個(gè)doCallbacks()方法,我們看到幾個(gè)方法分別是:
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);
還記得CALLBACK_ANIMATION這個(gè)標(biāo)志1嗎蟹略,我們之前在鏈表中添加回到的時(shí)候特地說明了這個(gè)CALLBACK_ANIMATION邀桑,其他的標(biāo)志分別對應(yīng)于Input事件,還有我們說過的這個(gè)對應(yīng)于動(dòng)畫科乎,接下來對應(yīng)的是視圖重繪三個(gè)重要回調(diào)。我們這里先看看這個(gè)doCallbacks()方法干啥:
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 {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
for (CallbackRecord c = callbacks; c != null; c = c.next) {
.......
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
這個(gè)方法剛進(jìn)來會(huì)取出mCallbackQueues[callbackType]贼急,比如我們傳進(jìn)來的callbackType是CALLBACK_ANIMATION(為1)茅茂,那么我們就會(huì)取出這個(gè)隊(duì)列對應(yīng)的1位置的單鏈表。extractDueCallbacksLocked這個(gè)方法我們不詳細(xì)看太抓,這個(gè)方法就是從單鏈表中取出符合當(dāng)前時(shí)間執(zhí)行動(dòng)畫的CallbackRecord空闲,然后從我們當(dāng)前取出來的這個(gè)節(jié)點(diǎn)開始遍歷分別調(diào)用他的run方法:
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
我們之前看到我們的token就是FRAME_CALLBACK_TOKEN,所以我們會(huì)調(diào)用if里面的代碼走敌,而且我們剛才介紹過了這個(gè)地方的action就是我們之前傳進(jìn)來的callback碴倾,這個(gè)地方重新貼一下:
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
所以我們就會(huì)回調(diào)這里的doFrame,我們看看這里面做了些什么掉丽,首先我們看第一個(gè)方法doAnimationFrame()跌榔,這里getProvider().getFrameTime()獲取的是開始的幀時(shí)間:
private void doAnimationFrame(long frameTime) {
int size = mAnimationCallbacks.size();
long currentTime = SystemClock.uptimeMillis();
for (int i = 0; i < size; i++) {
final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
if (callback == null) {
continue;
}
if (isCallbackDue(callback, currentTime)) {
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
cleanUpList();
}
這個(gè)方法是遍歷mAnimationCallbacks,這個(gè)是什么呢捶障?這個(gè)我們之前已經(jīng)說過了其實(shí)僧须,在ValueAnimator的start(boolean playBackwards)方法里面的animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale))添加進(jìn)去的,這個(gè)地方this就是ValueAnimator项炼。所以這個(gè)地方的回調(diào)其實(shí)是ValueAnimator里面(實(shí)現(xiàn)了AnimationHandler.AnimationFrameCallback接口)担平,且回調(diào)接口有兩個(gè)方法:doAnimationFrame(long frameTime)和commitAnimationFrame(long frameTime)。所以我們很明了锭部,后面遍歷調(diào)用callback.doAnimationFrame(frameTime)其實(shí)就是調(diào)用ValueAnimator的這個(gè)方法暂论,我們來看看這個(gè)方法:
public final void doAnimationFrame(long frameTime) {
AnimationHandler handler = AnimationHandler.getInstance();
.........
final long currentTime = Math.max(frameTime, mStartTime);
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
endAnimation();
}
}
我們看到這個(gè)方法得到了當(dāng)前的時(shí)間currentTime然后傳進(jìn)animateBasedOnTime方法,我們看下這個(gè)方法干啥了:
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
if (mRunning) {
final long scaledDuration = getScaledDuration();
final float fraction = scaledDuration > 0 ?
(float)(currentTime - mStartTime) / scaledDuration : 1f;
final float lastFraction = mOverallFraction;
final boolean newIteration = (int) fraction > (int) lastFraction;
final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
(mRepeatCount != INFINITE);
if (scaledDuration == 0) {
// 0 duration animator, ignore the repeat count and skip to the end
done = true;
} else if (newIteration && !lastIterationFinished) {
// Time to repeat
if (mListeners != null) {
int numListeners = mListeners.size();
for (int i = 0; i < numListeners; ++i) {
mListeners.get(i).onAnimationRepeat(this);
}
}
} else if (lastIterationFinished) {
done = true;
}
mOverallFraction = clampFraction(fraction);
float currentIterationFraction = getCurrentIterationFraction(mOverallFraction);
animateValue(currentIterationFraction);
}
return done;
}
首先判斷是否是running狀態(tài)拌禾,顯然我們從前面知道是true的取胎。我們前面不用去認(rèn)真管,直接看到最后調(diào)用animateValue()方法蹋砚,傳進(jìn)去的參數(shù)就是動(dòng)畫執(zhí)行完成度的比率扼菠。我們看下這個(gè)方法:
@CallSuper
void animateValue(float fraction) {
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].calculateValue(fraction);
}
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
我們看到這個(gè)方法首先是調(diào)用插值器的getInterpolation()方法,這個(gè)插值器我們知道我們根據(jù)我們傳進(jìn)來的完成度fraction來重新計(jì)算坝咐,我們?nèi)绻远x插值器也就是要重寫這個(gè)方法循榆。然后遍歷mValues這個(gè)List(這就是PropertyValuesHolder[]數(shù)組),然后調(diào)用他的calculateValue()方法:
@Override
void calculateValue(float fraction) {
mIntAnimatedValue = mIntKeyframes.getIntValue(fraction);
}
這個(gè)方法是獲取這個(gè)完成度所對應(yīng)的值墨坚。最后回調(diào)mUpdateListeners秧饮,如果用戶注冊了這個(gè)監(jiān)聽這時(shí)候就會(huì)被回調(diào)映挂。我們看會(huì)animateBasedOnTime方法,這個(gè)方法里面會(huì)返回一個(gè)done盗尸,如果這個(gè)動(dòng)畫已經(jīng)完成柑船,這個(gè)done就會(huì)返回true執(zhí)行endAnimation()方法,如果沒完成就返回false泼各,不執(zhí)行結(jié)束方法鞍时。我們繼續(xù)回到AnimationHandler的doAnimationFrame方法中,看到下一句:
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
我們看到這邊也是調(diào)用getProvider()方法即得到MyFrameCallbackProvider方法扣蜻,然后調(diào)用這個(gè)類的postCommitCallback方法逆巍,我們一步一步像前面一樣跟進(jìn)去,我們發(fā)現(xiàn)也是到達(dá)Choreographer類中的postCallbackDelayedInternal()這個(gè)方法莽使,然后又會(huì)調(diào)用addCallbacks方法锐极,我們發(fā)現(xiàn)又循環(huán)回來了。就這樣我們動(dòng)畫就一直計(jì)算fraction然后循環(huán)執(zhí)行芳肌。
總結(jié):到這里動(dòng)畫的源碼分析已經(jīng)講解完畢了灵再,因?yàn)榱鞒烫啵绻治雎┑恼堃娬徱隗裕欢牡胤娇梢蕴岢鰜眙崆ǎ赖目梢越獯稹?/strong>