1. 程式人生 > >Android屬性動畫原始碼解析

Android屬性動畫原始碼解析

屬性動畫是Android開發中常用的知識,網上大多數文章都是基於屬性動畫的用法來解說的,本文基於屬性動畫的原始碼,從原始碼角度去一探屬性動畫的究竟。

屬性動畫有兩個非常重要的類,分別是ObjectAnimator和ValueAnimator,其中前者繼承了後者,前者是對屬性動畫的api提供了更好的一層封裝,方便開發者使用。屬性動畫常見的用法如下:

ObjectAnimator animator = ObjectAnimator.ofFloat(targetView, "translationX", 100);

animator.setInterpolator(new LinearInterpolator());
animator.setEvaluator(new FloatEvaluator());
animator.setDuration(100);
animator.start();

上面涉及到兩個概念,插值器Interpolator和估值器Evaluator,插值器表示動畫播放過程中的某個時間點播放進度的百分比,是用來控制播放速率的,估值器用來計算某個播放進度點需要改變的view的屬性值,Evaluator.evaluate(float fraction, T startValue, T endValue) 是核心方法,fraction是進度百分比,startValue 和 endValue 表示動畫的起始值和結束值,通過這個三個值去計算對應的view的屬性值。

下面我們就基於上面的使用方式去追蹤分析一下原始碼,首先點進ofFloat方法如下:

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
    }


//new ObjectAnimator程式碼如下
private ObjectAnimator(Object target, String propertyName) {
        setTarget(target);
        setPropertyName(propertyName);
    }


//setFloatValues方法的程式碼如下
    @Override
    public void setFloatValues(float... 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.ofFloat(mProperty, values));
            } else {
                setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
            }
        } else {
            super.setFloatValues(values);
        }
    }

可以看到首先建立一個ObjectAnimator物件,進行動畫view和動畫屬性名字的設定,然後通過setFloatValues設定我們一個動畫值。上面出現了一個PropertyValuesHolder.ofFloat方法,看起來像是將屬性相關值儲存在一個類中,我們進去看看:


 public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
        return new FloatPropertyValuesHolder(property, values);
    }


//下一步程式碼
public FloatPropertyValuesHolder(Property property, float... values) {
            super(property);
            setFloatValues(values);
            if (property instanceof  FloatProperty) {
                mFloatProperty = (FloatProperty) mProperty;
            }
        }


//setFloatValues的程式碼
public void setFloatValues(float... values) {
            super.setFloatValues(values);
            mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
        }

//------
public void setFloatValues(float... values) {
        mValueType = float.class;
        mKeyframes = KeyframeSet.ofFloat(values);
    }


我們可以看到FloatPropertyValuesHolder是用來儲存相關屬性值的,其中出現了一個FloatKeyframes類,我們去看看這個類:

 // 通過這個方法去儲存我們設定的屬性values
  public static KeyframeSet ofFloat(float... values) {
        boolean badValue = false;
        int numKeyframes = values.length;
        FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
        if (numKeyframes == 1) {
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
            keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
            if (Float.isNaN(values[0])) {
                badValue = true;
            }
        } else {
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
            for (int i = 1; i < numKeyframes; ++i) {
                keyframes[i] =
                        (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
                if (Float.isNaN(values[i])) {
                    badValue = true;
                }
            }
        }
        if (badValue) {
            Log.w("Animator", "Bad value (NaN) in float animator");
        }
        return new FloatKeyframeSet(keyframes);
    }

  在KeyframeSet的ofFloat方法中,我們建立一個FloatKeyframes陣列,將屬性values儲存在陣列中。其中Keyframe我們翻譯叫關鍵幀,代表動畫執行過程中的一些重要的幀,比如開始、結束、中間值等等。這些值在動畫執行過程中都會用到。

到這裡分析完setValues(PropertyValuesHolder.ofFloat(mProperty, values))中的PropertyValuesHolder.ofFloat方法的作用,下面來看看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;
    }

我們這裡對mValues進行了賦值,這個值後面會經常用到,然後將屬性holder儲存到hashmap中,其中key是屬性名。到這裡我們分析完了ObjectAnimator.ofFloat(targetView, "translationX", 100);方法的整個過程,其實就是將我們設定的屬性值儲存起來。然後還有插值器和估值器,程式碼如下

//儲存插值器 
@Override
    public void setInterpolator(TimeInterpolator value) {
        if (value != null) {
            mInterpolator = value;
        } else {
            mInterpolator = new LinearInterpolator();
        }
    }


//儲存估值器
public void setEvaluator(TypeEvaluator value) {
        if (value != null && mValues != null && mValues.length > 0) {
            mValues[0].setEvaluator(value);
        }
    }

其中插值器是儲存在ValueAnimator中,而估值器是儲存在PropertyValuesHolder中。

上面屬性值都已經設定好了,開始進入start方法,這個方法裡面程式碼非常複雜,我們儘量簡要一點說明吧,做好準備進入start階段,先來看看start進入的關鍵程式碼:

 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;
            }
        }
        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;
        //關鍵一
        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);
            }
        }
    }

我們從中挑出三個關鍵的方法逐一分析:

1.addAnimationCallback(0);

2.startAnimation();

3.setCurrentPlayTime(0);

下面我們來看看addAnimationCallback方法,

private void addAnimationCallback(long delay) {
        if (!mSelfPulse) {
            return;
        }
        getAnimationHandler().addAnimationFrameCallback(this, delay);
    }


//AnimationHandler的addAnimationFrameCallback方法程式碼
   public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
        if (mAnimationCallbacks.size() == 0) {
            //程式首先會執行這裡,因為此時mAnimationCallbacks中還沒有新增元素
            getProvider().postFrameCallback(mFrameCallback);
        }
        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);
        }

        if (delay > 0) {
            mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
        }
    }

這裡會呼叫AnimationHandler的新增監聽方法,其中又會轉到getProvider().postFrameCallback(mFrameCallback)的執行,我們先來看看那個mFrameCallback這個引數,再去追蹤getProvider方法

 private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime());
            if (mAnimationCallbacks.size() > 0) {
                //重複呼叫
                getProvider().postFrameCallback(this);
            }
        }
    };

這個回撥介面中,我們發現一個有趣的地方,就是會重複呼叫getProvider().postFrameCallback,這種反覆操作的執行,有點像動畫的繪製了。那我們先轉去看看getProvider方法:

private AnimationFrameCallbackProvider getProvider() {
        if (mProvider == null) {
            mProvider = new MyFrameCallbackProvider();
        }
        return mProvider;
    }



   //其中MyFrameCallbackProvider類的程式碼
   final Choreographer mChoreographer = Choreographer.getInstance();

        @Override
        public void postFrameCallback(Choreographer.FrameCallback callback) {
            mChoreographer.postFrameCallback(callback);
        }

這裡出現了一個新類Choreographer,我們去看看:

//Choreographer類的方法
public void postFrameCallback(FrameCallback callback) {
        postFrameCallbackDelayed(callback, 0);
    }


  //往下走
  public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
        if (callback == null) {
            throw new IllegalArgumentException("callback must not be null");
        }

        postCallbackDelayedInternal(CALLBACK_ANIMATION,
                callback, FRAME_CALLBACK_TOKEN, delayMillis);
    }


    //往下走
    private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG_FRAMES) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + 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);
            }
        }
    }

程式又走了幾步,經過判斷,我們的程式碼會走到scheduleFrameLocked(now),下面我們進去看看:

    private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            if (USE_VSYNC) {
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "Scheduling next frame on 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);
            }
        }
    }

上面程式碼有點多,我們只看程式執行的部分,上面的會通過mHandler傳送一個MSG_DO_SCHEDULE_VSYNC訊息,所以我們又去看看handler是怎麼處理這個訊息的:

   private final class FrameHandler extends Handler {
        public FrameHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_DO_FRAME:
                    doFrame(System.nanoTime(), 0);
                    break;
                case MSG_DO_SCHEDULE_VSYNC:
                    doScheduleVsync();
                    break;

                //這裡
                case MSG_DO_SCHEDULE_CALLBACK:
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
    }


   //下一步
   void doScheduleCallback(int callbackType) {
        synchronized (mLock) {
            if (!mFrameScheduled) {
                final long now = SystemClock.uptimeMillis();
                if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                    scheduleFrameLocked(now);
                }
            }
        }
    }

通過上面可以看到程式碼會執行到scheduleFrameLocked(now)方法,進去看看:

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        if (USE_VSYNC) {
            ……
            if (isRunningOnLooperThreadLocked()) {
                scheduleVsyncLocked();
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        }
        ……
    }
}

上面的程式碼會執行到scheduleVsyncLocked()方法,

private void scheduleVsyncLocked() {
        mDisplayEventReceiver.scheduleVsync();
    }


  //其中DisplayEventReceiver類的程式碼
  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);
        }
    }

到這裡的時候,呼叫了一個jni方法,呵呵!其中引數mReceiverPtr是一個 jni 層指向 DisplayEventReceiver(子類 FrameDisplayEventReceiver) 的指標,jni 方法會回撥 FrameDisplayEventReceiver.onVsync() 方法,我們姑且不探究jni層是如何實現的,繼續看onVsync方法的程式碼:

    @Override
        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {

            //。。。。。省略程式碼

            mTimestampNanos = timestampNanos;
            mFrame = frame;
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);

            }

這裡通過 mHandler 呼叫自身 FrameDisplayEventReceiver.run()方法,

public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }



//doFrame的程式碼
void doFrame(long frameTimeNanos, int frame) {
    final long startNanos;
    synchronized (mLock) {
        ……

    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);
    }

    ……
}

我們可以看到開始執行各種doCallbacks方法了,這個是關鍵,下面快點進入去看看

void doCallbacks(int callbackType, long frameTimeNanos) {
        CallbackRecord callbacks;
        synchronized (mLock) {
         
            final long now = System.nanoTime();
            //獲取我們之前儲存的callbacks
            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) {
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "RunCallback: type=" + callbackType
                            + ", action=" + c.action + ", token=" + c.token
                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                }
                //執行callback
                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);
        }
    }

其中我們會獲取到之前儲存的各種callback,然後通過run方法執行callback,其中c就是mCallbackQueues在下面的方法中儲存的元素

    private void postCallbackDelayedInternal(int callbackType,

        ...................

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            //在這裡儲存的
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

         ................... 

        }
    }

下面我們看看CallbackRecord 的run方法:

    public void run(long frameTimeNanos) {
            if (token == FRAME_CALLBACK_TOKEN) {
                ((FrameCallback)action).doFrame(frameTimeNanos);
            } else {
                ((Runnable)action).run();
            }
        }
    }

這裡的action就是我們上面執行過的mFrameCallback這個引數,再看看下面的程式碼清晰一點,因為繞了太多了,到這裡我們就知道了繪製動畫的核心,因為這個回撥會反覆執行,這就達到了繪製的效果。下面我要去看看下面的doAnimationFrame方法了

 private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime());
            if (mAnimationCallbacks.size() > 0) {
                //重複呼叫
                getProvider().postFrameCallback(this);
            }
        }
    };

程式碼:

 private void doAnimationFrame(long frameTime) {
        long currentTime = SystemClock.uptimeMillis();
        final int size = mAnimationCallbacks.size();
        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();
    }

看關鍵callback.doAnimationFrame(frameTime),這個callback是ValueAnimator中的

getAnimationHandler().addAnimationFrameCallback(this, delay)

新增的,我們它所實現的介面方法:

 public final boolean doAnimationFrame(long frameTime) {
        
        ...........
        直接看這裡
        boolean finished = animateBasedOnTime(currentTime);

        if (finished) {
            endAnimation();
        }
        return finished;
    }

我們繼續看 animateBasedOnTime(currentTime)

boolean animateBasedOnTime(long currentTime) {
    boolean done = false;
    if (mRunning) {
        ……
        animateValue(currentIterationFraction);
    }
    return done;
}


//往下看
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);
        }
    }
}

在這裡高興地看到了mValues的呼叫,好像是要賦fraction的值,就是播放進度,後面還呼叫了onAnimationUpdate方法,我們知道在ValueAnimator中有一個動畫更新的回撥,好像這裡找到了被呼叫的地方了

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            ……
            ……
        }
});

剛剛看的是ValueAnimator的方法,下面我們去ObjectAnimator中的animateValue方法

    @Override
    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) {
            mValues[i].setAnimatedValue(target);
        }
    }

我們看到了mValues[i].setAnimatedValue(target)關鍵點,我們知道mValues中儲存的是FloatPropertyValuesHolder 物件,就是我們所儲存的各個屬性值,下面我們去看看具體的方法實現

void setAnimatedValue(Object target) {
        if (mFloatProperty != null) {
            mFloatProperty.setValue(target, mFloatAnimatedValue);
            return;
        }
        if (mProperty != null) {
            mProperty.set(target, mFloatAnimatedValue);
            return;
        }
        if (mJniSetter != 0) {
            nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);
            return;
        }
        if (mSetter != null) {
            try {
                mTmpValueArray[0] = mFloatAnimatedValue;
                mSetter.invoke(target, mTmpValueArray);
            } catch (InvocationTargetException e) {
                Log.e("PropertyValuesHolder", e.toString());
            } catch (IllegalAccessException e) {
                Log.e("PropertyValuesHolder", e.toString());
            }
        }
    }

到這裡有幾個if判斷,我們不知道程式會走哪一步,那我們先放一下,回到最前面,我們還有兩個方法沒追蹤,下面我們來看看startAnimation()方法:

private void startAnimation() {
    if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                System.identityHashCode(this));
    }

    mAnimationEndRequested = false;
    initAnimation();
    mRunning = true;
    if (mSeekFraction >= 0) {
        mOverallFraction = mSeekFraction;
    } else {
        mOverallFraction = 0f;
    }
    if (mListeners != null) {
        notifyStartListeners();
    }
}

這裡有一個初始化的initAnimation()方法,下面我們看看

void initAnimation() {
    if (!mInitialized) {
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].init();
        }
        mInitialized = true;
    }
}


//看看 FloatPropertyValuesHolder.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);
    }
}

上面我們呼叫到FloatPropertyValuesHolder.init()方法,好像沒什麼值得發現的,下面我們來看看ObjectAnimator的initAnimation方法:

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) {
                mValues[i].setupSetterAndGetter(target);
            }
        }
        super.initAnimation();
    }
}

會呼叫 mValues[i].setupSetterAndGetter(target) 即FloatPropertyValuesHolder.setupSetterAndGetter(target),繼續跟進

void setupSetterAndGetter(Object target) {
        setupSetter(target.getClass());
    }


//繼續
void setupSetter(Class targetClass) {
        if (mJniSetter != 0) {
            return;
        }
        synchronized(sJNISetterPropertyMap) {
            HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
            boolean wasInMap = false;
            if (propertyMap != null) {
                wasInMap = propertyMap.containsKey(mPropertyName);
                if (wasInMap) {
                    Long jniSetter = propertyMap.get(mPropertyName);
                    if (jniSetter != null) {
                        mJniSetter = jniSetter;
                    }
                }
            }
            if (!wasInMap) {
                String methodName = getMethodName("set", mPropertyName);
                calculateValue(0f);
                float[] values = (float[]) getAnimatedValue();
                int numParams = values.length;
                try {
                    mJniSetter = nGetMultipleFloatMethod(targetClass, methodName, numParams);
                } catch (NoSuchMethodError e) {
                    // try without the 'set' prefix
                    try {
                        mJniSetter = nGetMultipleFloatMethod(targetClass, mPropertyName,
                                numParams);
                    } catch (NoSuchMethodError e2) {
                        // just try reflection next
                    }
                }
                if (propertyMap == null) {
                    propertyMap = new HashMap<String, Long>();
                    sJNISetterPropertyMap.put(targetClass, propertyMap);
                }
                propertyMap.put(mPropertyName, mJniSetter);
            }
        }
    }
}

這裡會對mJniSetter 進行賦值,所以回到上面幾個if的判斷中,我們可以知道,程式會走

 if (mJniSetter != 0) {
            nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);
            return;
        }

這裡會通過jni指標,修改對應的屬性引數,即view.setTranslanteX(value)方法。程式碼到這裡,我們完成了view屬性的設定,整個動畫過程中,隨著動畫的進度不斷改變,屬性值也會不斷改變,然後通過我們的設定,目標view的屬性值也會不斷改變,從而達到屬性動畫的效果。

下面我們看看最後第一個關鍵方法setCurrentPlayTime(0)

public void setCurrentPlayTime(long playTime) {
    float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
    setCurrentFraction(fraction);
}


// setCurrentPlayTime(0) 還是會呼叫 setCurrentFraction(mSeekFraction)
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);
}

可以看到上面會呼叫到animateValue(currentIterationFraction)方法,我們知道這個方法就是對view屬性的更新,所以可以知道在呼叫了startAnimation()之後,就會立即進行一次view的更新操作,此時引數fraction為0。

上面就是屬性動畫原始碼解析全過程了,實在是太長了,閱讀原始碼我們還是要抓住關鍵的步驟,不能沉溺於不重要的細節,在開發路上我們共勉吧!