【源码简析】ObjectAnimator & ValueAnimator

【疑问1】ObjectAnimator如何通过"translationX"这样实现的动画
【疑问2】ValueAnimator在INFINITE模式下,为什么cancel和end会失效(误会?其他未知bug?)

【1】ObjectAnimator.ofFloat(...)着手
先附上创建ObjectAnimator的源码

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { //->(1) ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setFloatValues(values); return anim; }(1) private ObjectAnimator(Object target, String propertyName) { //->(2) setTarget(target); //->(3) setPropertyName(propertyName); }(2) public void setTarget(@Nullable Object target) { final Object oldTarget = getTarget(); if (oldTarget != target) { if (isStarted()) { cancel(); } mTarget = target == null ? null : new WeakReference(target); // New target should cause re-initialization prior to starting mInitialized = false; } } (3) 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; }
代码(2)setTarget是设置目标View
代码(3)setPropertyName是设置具体属性
设置完 目标View 和 目标属性 后略过其他,直接分析start
public void start() { 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(); }

【【源码简析】ObjectAnimator & ValueAnimator】ObjectAnimator是ValueAnimator的子类,super.start()就是ValueAnimator的start()
public void start() { start(false); }//playBackwards是false,表示不reverse执行动画 private void start(boolean playBackwards) { if (Looper.myLooper() == null) { throw new AndroidRuntimeException("Animators may only be run on Looper threads"); } mReversing = playBackwards; mSelfPulse = !mSuppressSelfPulseRequested; // Special case: reversing from seek-to-0 should act as if not seeked at all. if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) { if (mRepeatCount == INFINITE) { // Calculate the fraction of the current iteration. float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction)); mSeekFraction = 1 - fraction; } else { mSeekFraction = 1 + mRepeatCount - mSeekFraction; } } (1) 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 = -1; mFirstFrameTime = -1; mStartTime = -1; (2) addAnimationCallback(0); (3) if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) { // 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); } } }

(1)此时mStarted为true,mRunning为false。说明属性动画的Start状态先于Running状态,符合后面的注释描述。
(2)addAnimationHandler中涉及到Choreographer,以此实现动画。
private void addAnimationCallback(long delay) { if (!mSelfPulse) { return; } getAnimationHandler().addAnimationFrameCallback(this, delay); }//每个线程持有一个单例,基于ThreadLocal实现的 public AnimationHandler getAnimationHandler() { return AnimationHandler.getInstance(); }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)); } }

第一个start,会执行代码: getProvider().postFrameCallback(mFrameCallback);
追踪代码,发现getProvider()会得到MyFrameCallbackProvider的实例类,从这里就涉及到Choreographer了
private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {final Choreographer mChoreographer = Choreographer.getInstance(); @Override public void postFrameCallback(Choreographer.FrameCallback callback) { mChoreographer.postFrameCallback(callback); }... }

这里不分析Choreographer,记住callback是mFrameCallback。后续流程会将mFrameCallback加入Choreographer中的mCallbackQueues,并开始监听下一个Vsync信号(当信号来到时就会处理动画逻辑)。追踪代码的过程中会有这么一行代码,后面分析会涉及到。
postCallbackDelayedInternal(CALLBACK_ANIMATION,callback, FRAME_CALLBACK_TOKEN, delayMillis);

private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable { private boolean mHavePendingVsync; private long mTimestampNanos; private int mFrame; public FrameDisplayEventReceiver(Looper looper, int vsyncSource) { super(looper, vsyncSource); }@Override public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { ...mTimestampNanos = timestampNanos; mFrame = frame; //利用同步屏障,立即执行run()方法 Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); }@Override public void run() { mHavePendingVsync = false; doFrame(mTimestampNanos, mFrame); } }

接收信号,走到onVsync中,并通过Handler执行到run() -> doFrame(...)方法。在doFrame中,会调用doCallbacks(...)
void doFrame(long frameTimeNanos, int frame) { final long startNanos; ...try { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame"); 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); }... }void doCallbacks(int callbackType, long frameTimeNanos) { CallbackRecord callbacks; ... try { Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]); 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); } } ... }private static final class CallbackRecord { public CallbackRecord next; public long dueTime; public Object action; // Runnable or FrameCallback public Object token; public void run(long frameTimeNanos) { if (token == FRAME_CALLBACK_TOKEN) { ((FrameCallback)action).doFrame(frameTimeNanos); } else { ((Runnable)action).run(); } } }

doCallbacks(...)又会进一步执行mCallbackQueues中的“callback”。对于ObjectAnimator,我们本次仅关注Choreographer.CALLBACK_ANIMATION类型的callback。类似于Handler的Message,根据时间判断,获取run的callback并按顺序执行。上面说到会涉及到这段代码,这里就用到了
postCallbackDelayedInternal(CALLBACK_ANIMATION,callback, FRAME_CALLBACK_TOKEN, delayMillis);
因为FRAME_CALLBACK_TOKEN,所以最终会回归到之前的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); } } };

doAnimationFrame中执行一些动画状态相关的处理,并通过boolean finished = animateBasedOnTime(currentTime); 计算属性值,所以属性动画是通过ANIMATION类型的callback不断计算属性值。
doAnimationFrame执行完后,根据mAnimationCallbacks判断是否还有需要继续执行的属性动画,如果有,则继续利用getProvider().postFrameCallback(this); 循环监听Vsync信号更新界面。而
这里涉及到一点,就是只有当mAnimationCallbacks的size为0时,才会将callback加入Choreographer,后续的都是在复用之前的同一个Vsync信号。
为了让动画真正执行,肯定需要不断计算更新view的属性,并触发绘制。回到最开始,ValueAnimator的start(...)方法中,接着addAnimationCallback往后执行。
private void start(boolean playBackwards) { ... addAnimationCallback(0); if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) { // 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); } } }

mStartDelay是否延迟
mSeekFraction执行百分比
mReversing动画是否反转执行
对于默认情况 最开始 mSeekFraction为-1,mReversing为false,而mStartDelay为为0,所以会走进逻辑。但是当我们设置delay延迟后,就走不进来了?这时可以看看doAnimationFrame会发现里面有段逻辑是专门处理这种情况。当然还会有各种各样的情况,等遇到时,再补上分析的代码吧。接着分析调用流程startAnimation() -> initAnimation() -> notifyStartListeners()
//ObjectAnimator.java void initAnimation() { if (!mInitialized) { // mValueType may change due to setter/getter setup; do this before calling super.init(), // which uses mValueType to set up the default type evaluator. final Object target = getTarget(); if (target != null) { final int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { //设置getter,setter方法 mValues[i].setupSetterAndGetter(target); } } super.initAnimation(); } }//ValueAnimator.java void initAnimation() { if (!mInitialized) { int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { mValues[i].init(); } mInitialized = true; } }

mValues是创建ObjectAnimator示例时生成的 PropertyValuesHolder[] 数组,那么往下追踪PropertyValuesHolder的init()方法。
void init() { if (mEvaluator == null) { // We already handle int and float automatically, but not their Object // equivalents mEvaluator = (mValueType == Integer.class) ? sIntEvaluator : (mValueType == Float.class) ? sFloatEvaluator : null; } if (mEvaluator != null) { // KeyframeSet knows how to evaluate the common types - only give it a custom // evaluator if one has been set on this class mKeyframes.setEvaluator(mEvaluator); } }

就是为每个属性设置估值器,暂不深入。再之后就是调用setCurrentPlayTime,其实内部也是调用setCurrentFraction
public void setCurrentPlayTime(long playTime) { float fraction = mDuration > 0 ? (float) playTime / mDuration : 1; setCurrentFraction(fraction); }public void setCurrentFraction(float fraction) { initAnimation(); fraction = clampFraction(fraction); mStartTimeCommitted = true; // do not allow start time to be compensated for jank if (isPulsingInternal()) { long seekTime = (long) (getScaledDuration() * fraction); long currentTime = AnimationUtils.currentAnimationTimeMillis(); // Only modify the start time when the animation is running. Seek fraction will ensure // non-running animations skip to the correct start time. mStartTime = currentTime - seekTime; } else { // If the animation loop hasn't started, or during start delay, the startTime will be // adjusted once the delay has passed based on seek fraction. mSeekFraction = fraction; } mOverallFraction = fraction; final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing); animateValue(currentIterationFraction); }

计算fraction信息,调用animateValue
//ObjectAnimator.java void animateValue(float fraction) { final Object target = getTarget(); if (mTarget != null && target == null) { // We lost the target reference, cancel and clean up. Note: we allow null target if the /// target has never been set. cancel(); return; }super.animateValue(fraction); int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { //实际就是调用对应的setter方法 mValues[i].setAnimatedValue(target); } }//ValueAnimator.java 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); } } }

对于ObjectAnimator,mValues不为空,mUpdatelisteners为空,所以关键代码是 mValues[i].calculateValue(fraction);
对于ValueAnimator,使用时会addUpdateListener,所以mUpdateListeners不为空。
所以对于ObjectAnimator.ofFloat(...),对于每个属性,调用calculateValue计算属性值,再调用setAnimatedValue调用setter方法。在setter方法中又会调用invalidate触发重新绘制。到这里ObjectAnimator的绘制流程大致就分析完了,其实这里还欠缺生成ObjectAnimator示例的分析。
【疑问2】上述分析其实已经涉及到ValueAnimator动画的一些流程。那么分析cancel和end应该就可以得到想要的结果。
public void cancel() { ... endAnimation(); }public void end() { ... endAnimation(); }

关键要分析endAnimation方法
private void endAnimation() { if (mAnimationEndRequested) { return; } removeAnimationCallback(); mAnimationEndRequested = true; mPaused = false; boolean notify = (mStarted || mRunning) && mListeners != null; if (notify && !mRunning) { // If it's not yet running, then start listeners weren't called. Call them now. notifyStartListeners(); } mRunning = false; mStarted = false; mStartListenersCalled = false; mLastFrameTime = -1; mFirstFrameTime = -1; mStartTime = -1; if (notify && mListeners != null) { ArrayList tmpListeners = (ArrayList) mListeners.clone(); int numListeners = tmpListeners.size(); for (int i = 0; i < numListeners; ++i) { tmpListeners.get(i).onAnimationEnd(this, mReversing); } } // mReversing needs to be reset *after* notifying the listeners for the end callbacks. mReversing = false; if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(), System.identityHashCode(this)); } }

其实就是调用Listeners回调,并且重置标志位等一些基本操作。关键是removeCallback,也就是将当前ValueAnimator从列表中移除,那么后续Choreographer处理时,就不会再执行动画。有意思的事情是,当我分析完这部分代码。再次运行代码验证时,疑问2的问题竟然不再复现了。。。










    推荐阅读