前言
Android 的動(dòng)畫(huà)分為幀動(dòng)畫(huà),補(bǔ)間動(dòng)畫(huà),屬性動(dòng)畫(huà),這些概念都是老生常談了,那它們底層的邏輯到底是怎樣的呢,我們這次透過(guò)表面看本質(zhì),到底內(nèi)部是怎么處理動(dòng)畫(huà)的
簡(jiǎn)單的動(dòng)畫(huà)大概有移動(dòng)/縮放/旋轉(zhuǎn)等幾種類(lèi)型,屬性動(dòng)畫(huà)中是怎樣處理這些的呢?
我們化繁為簡(jiǎn),從動(dòng)畫(huà)的啟動(dòng)開(kāi)始入手,了解 Choreographer 是怎樣轉(zhuǎn)換 VSYNC 信號(hào)的
提出問(wèn)題
- VSYNC 是什么 ?
- Choreographer 在動(dòng)畫(huà) start() 中,實(shí)現(xiàn)了什么功能
源碼分析
從 ObjectAnimator.ofInt(mButton, "width", 500).setDuration (5000).start() 入手
- ofInt() 做了什么
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
// 這里只是創(chuàng)建 ObjectAnimator 對(duì)象
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setIntValues(values);
return anim;
}
private ObjectAnimator(Object target, String propertyName) {
//設(shè)置動(dòng)畫(huà)的目前 View
setTarget(target);
setPropertyName(propertyName);
}
public void setTarget(@Nullable Object target) {
final Object oldTarget = getTarget();
if (oldTarget != target) {
// 取消之前的
if (isStarted()) {
cancel();
}
// 重新設(shè)置 targetView ,這里使用了弱引用
mTarget = target == null ? null : new WeakReference<Object>(target);
mInitialized = false;
}
}
public void setPropertyName(@NonNull String propertyName) {
if (mValues != null) {
// 移除掉HashMap的舊值,至于為什么要這樣,等會(huì)再看看
PropertyValuesHolder valuesHolder = mValues[0];
String oldName = valuesHolder.getPropertyName();
valuesHolder.setPropertyName(propertyName);
mValuesMap.remove(oldName);
//當(dāng)前的屬性 put 到表中 mValuesMap.put(propertyName, valuesHolder);
}
mPropertyName = propertyName;
mInitialized = false;
}
- start() 做了什么
public void start() {
// AnimationHandler 需要了解下功能
// 這里將之前取消掉,然后調(diào)用父類(lèi)的 start()
AnimationHandler.getInstance().autoCancelBasedOn(this);
super.start();
}
/**
ObjectAnimator 的父類(lèi) VauleAnimator
**/
private void start(boolean playBackwards) {
// 一般不會(huì),因?yàn)樵谥骶€(xiàn)程執(zhí)行
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
// 是否重復(fù)執(zhí)行
mReversing = playBackwards;
mSelfPulse = !mSuppressSelfPulseRequested;
// AnimationHandler.addAnimationFrameCallback()
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
// 觸發(fā) onAnimationStart()
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);
}
}
/**
AnimationHandler.class
**/
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
// 根據(jù)是否有延時(shí)執(zhí)行,來(lái)放到不同的動(dòng)畫(huà)任務(wù)隊(duì)列中
// 若隊(duì)列為空,則直接 post
if (mAnimationCallbacks.size() == 0) {
// 這里實(shí)際是調(diào)用 Choreographer.scheduleFrameLocked(),發(fā)送一條異步消息
getProvider().postFrameCallback(mFrameCallback);
}
// 隊(duì)列不為空,就往隊(duì)尾插入
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
// 延時(shí)執(zhí)行,則放到另外的隊(duì)列中
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
有點(diǎn)繞了,先整理下思路,在調(diào)用開(kāi)始后,AnimationHandler 會(huì)創(chuàng)建一個(gè) Callback,放到隊(duì)列中,或者直接發(fā)送 Msg,這里的作用是什么呢?
實(shí)際上最終是向 native 注冊(cè) VSYNC 信號(hào)的監(jiān)聽(tīng),通過(guò) DisplayEventReceiver.scheduleVsync() 注冊(cè)的,當(dāng) VSYNC 信號(hào)到來(lái)時(shí),會(huì)觸發(fā) DisplayEventReceiver.dispatchVsync,進(jìn)而觸發(fā) FrameDisplayEventReceiver.onVsync()
// Called from native code.
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
onVsync(timestampNanos, physicalDisplayId, frame);
}
// 這里將 native 層的 VSYNC ,分發(fā)到 Java 層中
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
if (timestampNanos > now) {
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;
// 發(fā)送異步消息
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
VSYNC 是什么 ?
VSYNC 是垂直同步的意思,在 Android 應(yīng)用層意味著屏幕刷新,具體的 VSYNC 機(jī)制參考 Vsync 信號(hào)機(jī)制和 UI 刷新流程
Choreographer 在動(dòng)畫(huà) start() 中,實(shí)現(xiàn)了什么功能
注冊(cè)監(jiān)聽(tīng) VSYNC 信號(hào),并且在信號(hào)到來(lái)后,在 Java 層發(fā)送通知
Choreographer 原理
這個(gè)單獨(dú)開(kāi)一篇文章來(lái)講