• 12-属性动画源码分析


    属性动画的基本介绍

    ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0.3f, 1.0f);
    alphaAnim.setInterpolator(new LinearInterpolator());
    alphaAnim.setDuration(1000);
    alphaAnim.start();
    
    • 1
    • 2
    • 3
    • 4

    属性动画主要使用 ObjectAnimator 和 ValueAnimator 两个类,其中ObjectAnimator 是 ValueAnimator 的子类,ObjectAnimator 对 ValueAnimator 做了一层封装,实现了对属性值的自动改变,api调用更加简略

    一、ObjectAnimator 创建

    我们一般使用 ObjectAnimator 的静态方法去创建 ObjectAnimator 对象。例如上面的ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0.3f, 1.0f),我们来看下它里面是如何创建的

    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.调用了 ObjectAnimator 的私有构造方法

    private ObjectAnimator(Object target, String propertyName) {
        //设置目标对象
        setTarget(target);
        //设置属性名
        setPropertyName(propertyName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    首先设置目标对象

    public void setTarget(@Nullable Object target) {
        final Object oldTarget = getTarget();
        if (oldTarget != target) {
            //如果目标对象改变,比如从默认的null变为非null
            if (isStarted()) {
                //如果之前动画已经开始了,先取消掉
                cancel();
            }
            mTarget = target == null ? null : new WeakReference<Object>(target);
            // 新目标应在starting之前引起重新初始化
            mInitialized = false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    然后设置属性名

    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.
        //此时此处为null,必定不会走下面的方法块
        if (mValues != null) {
           ...
        }
        mPropertyName = propertyName;
        //新的property应该在启动之前引起重新初始化
        mInitialized = false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.然后调用了setFloatValues方法初始化

    @Override
    public void setFloatValues(float... values) {
        if (mValues == null || mValues.length == 0) {
            //mValue没有赋值过,所以进入if方法块
            if (mProperty != null) {
                setValues(PropertyValuesHolder.ofFloat(mProperty, values));
            } else {
                //由于只设置了mPropertyName,所以走此处else的方法块
                setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
            }
        } else {
            super.setFloatValues(values);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    由于此时mValues没有赋值过,所以会先执行PropertyValuesHolder.ofFloat(mPropertyName, values)方法进行创建PropertyValuesHolder

    public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
        return new FloatPropertyValuesHolder(propertyName, values);
    }
    
    • 1
    • 2
    • 3

    调用了 FloatPropertyValuesHolder 的构造方法创建 PropertyValuesHolder 对象,

    public FloatPropertyValuesHolder(String propertyName, float... values) {
        super(propertyName);
        setFloatValues(values);
    }
    
    • 1
    • 2
    • 3
    • 4

    先是使用了父类 PropertyValuesHolder 的构造方法初始化 propertyName

    private PropertyValuesHolder(String propertyName) {
        mPropertyName = propertyName;
    }
    
    • 1
    • 2
    • 3

    然后是 FloatPropertyValuesHolder 的 setFloatValues 方法

    public void setFloatValues(float... values) {
        super.setFloatValues(values);
        //FloatPropertyValuesHolder 自己的对象赋值。
        mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    先是调用了父类 PropertyValuesHolder 的 setFloatValues 方法

    public void setFloatValues(float... values) {
        //mValueType提供值的类型。此信息既可用于推导settergetter函数,也可用于推导TypeEvaluator的类型。
        mValueType = float.class;
        //定义此动画的一组关键帧(时间值对)。
        mKeyframes = KeyframeSet.ofFloat(values);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    先是赋值了mValueType,用于定义值得类型。有调用了 KeyframeSet.ofFloat 方法,生成动画的关键帧,我们再看下 KeyframeSet.ofFloat 方法

    public static KeyframeSet ofFloat(float... values) {
        boolean badValue = false;
        //记录values的个数,
        int numKeyframes = values.length;
        //创建关键帧数组,至少有两个值
        FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
        if (numKeyframes == 1) {
            //如果用户只给了一个值,第0个关键帧键值对为<0,0>,意思是fraction为0时值为0
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
            //第1个关键帧赋值为<1,values[0]>,意思是fraction为1时,值为values[0]
            keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
            if (Float.isNaN(values[0])) {
                badValue = true;
            }
        } else {
            //超过一个关键帧,先设置第0个关键帧为<0,values[0]>
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
            //然后依次设置第i个关键帧为<(i/(numKeyframes - 1)),values[i])>
            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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    这里使用穿的values数组,生成关键帧数组,然后使用这些关键帧数据生成 FloatKeyframeSet 对象。

    关键帧数组的生成规则是

    如果只有一个值,则有两个关键帧,第0个关键帧键值对为<0,0>,意思是fraction为0时值为0

    超过一个关键帧,先设置第0个关键帧为<0,values[0]>,然后依次设置第i个关键帧为<(i/(numKeyframes - 1)),values[i])>

    到这里我们往后翻,回到 setFloatValues(float… values) 方法,为了防止忘了,我们再看一遍

    @Override
    public void setFloatValues(float... values) {
       ...
           setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
       ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上面我们已经看了 PropertyValuesHolder.ofFloat 如何创建 FloatPropertyValuesHolder 对象,我们再继续看

    setValues方法。

     public void setValues(PropertyValuesHolder... values) {
         int numValues = values.length;
         //对mValues进行赋值
         mValues = values;
         //创建numValues个对象的map
         mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
         for (int i = 0; i < numValues; ++i) {
             PropertyValuesHolder valuesHolder = values[i];
             //根据PropertyName,将valuesHolder存储起了,便于查找
             mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
         }
         // New property/values/target should cause re-initialization prior to starting
         mInitialized = false;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    setValues方法是 ObjectAnimator 父类 ValueAnimator 类 的方法,此处根据PropertyName,将valuesHolder存储起了,便于后面查找

    看到这里好像只是一堆四处调用进行赋值对象初始化,没啥亮点,唯一复杂点的就是关键帧的生成。既然这样我们就看下动画的开发方法,start()方法

    二、ObjectAnimator 的start 方法

    @Override
    public void start() {
        ...
        super.start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此处除了一些我们不需要关注的代码外就是对父类 ValueAnimator#start 方法的调用了,我们进去看一下

    public void start() {
        start(false);
    }
    
    • 1
    • 2
    • 3

    调用了一个同名方法 start(boolean playBackwards) ,其中参数标志是否是向后播放,也就是是否是反着做动画,这里传的是false,在调用动画的reverse方法时,此处会传true,我们看下里面是怎样的

    private void start(boolean playBackwards) {
        //检查是有Looper,没有的话抛出异常
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        mReversing = playBackwards;
        mSelfPulse = !mSuppressSelfPulseRequested;
        if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
            ...
        }
        mStarted = true;
        mPaused = false;
        mRunning = false;
        mAnimationEndRequested = false;
        // 在调用start()时重置mLastFrameTime,以便如果动画正在运行,则调用start())会将动画置于开始了但尚未到达的第一帧阶段。
        mLastFrameTime = -1;
        mFirstFrameTime = -1;
        mStartTime = -1;
        //关键点1
        addAnimationCallback(0);
    
        if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
            // 如果没有开始延迟,请初始化动画并立即通知开始侦听器,以与先前的行为保持一致。否则,将其推迟到开始延迟后的第一帧。
            //关键点2
            startAnimation();
            if (mSeekFraction == -1) {
                // 无seek,从播放时间0开始。请注意,我们不使用分数0的原因是,对于持续时间为0的动画,我们希望与N前行为保持一致:立即跳至最终值。
                setCurrentPlayTime(0);
            } else {
                setCurrentFraction(mSeekFraction);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    这里有两个关键点,我们先来看第一个addAnimationCallback(0)方法

    addAnimationCallback方法

    private void addAnimationCallback(long delay) {
        if (!mSelfPulse) {
            return;
        }
        getAnimationHandler().addAnimationFrameCallback(this, delay);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里通过调用getAnimationHandler()方法获取对象,然后又调用了addAnimationFrameCallback方法,我们先看下getAnimationHandler()方法获取到了啥。

    public AnimationHandler getAnimationHandler() {
        return AnimationHandler.getInstance();
    }
    
    • 1
    • 2
    • 3

    继续看AnimationHandler.getInstance()

    public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
    public static AnimationHandler getInstance() {
        if (sAnimatorHandler.get() == null) {
            sAnimatorHandler.set(new AnimationHandler());
        }
        return sAnimatorHandler.get();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此处使用了 ThreadLocal 线程本地变量,使得对象线程单例,很明显是使用了new AnimationHandler()语句初始化了对象,我们进入AnimationHandler类里看下addAnimationFrameCallback方法

    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));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    我们又要看下 getProvider() 方法获取了什么对象

    private AnimationFrameCallbackProvider getProvider() {
        if (mProvider == null) {
            mProvider = new MyFrameCallbackProvider();
        }
        return mProvider;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    很明显是MyFrameCallbackProvider类的实例,我们再进去看下他的postFrameCallback方法

    final Choreographer mChoreographer = Choreographer.getInstance();
    @Override
    public void postFrameCallback(Choreographer.FrameCallback callback) {
        mChoreographer.postFrameCallback(callback);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    又交给了mChoreographer,再看下Choreographer的postFrameCallback方法

    public void postFrameCallback(FrameCallback callback) {
        postFrameCallbackDelayed(callback, 0);
    }
    
    • 1
    • 2
    • 3

    不说了,继续看

    public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
        if (callback == null) {
            throw new IllegalArgumentException("callback must not be null");
        }
        //注意这个类型CALLBACK_ANIMATION和FRAME_CALLBACK_TOKEN
        postCallbackDelayedInternal(CALLBACK_ANIMATION,
                                    callback, FRAME_CALLBACK_TOKEN, delayMillis);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    private void postCallbackDelayedInternal(int callbackType,
                Object action, Object token, long delayMillis) {
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            //这里的action就是之前我们传入的action,这里将其添加到了queues里
            //注意这里按照callbackType进行了分组,当前的类型是CALLBACK_ANIMATION
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
    
            if (dueTime <= now) {
                //我们的delay一直为0,走这里
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    先看一下mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token)语句

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    这里通过obtainCallbackLocked方法获取了一个对象,然后将对象按照dueTime顺序插入到了一个链表里

    再看下obtainCallbackLocked方法

    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;
        //注意此处token为FRAME_CALLBACK_TOKEN,后面会用到
        callback.token = token;
        return callback;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    很明显此处获取了一个CallbackRecord 对象,然后把之前传过来的信息记录了下来,注意这个action是之前我们穿过来的callback。

    我们再回到postCallbackDelayedInternal方法

    private void postCallbackDelayedInternal(int callbackType,
                Object action, Object token, long delayMillis) {
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            ...
            if (dueTime <= now) {
                //我们的delay一直为0,走这里
                scheduleFrameLocked(now);
            } else {
               ...
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    由于我们的delay一直为0,走scheduleFrameLocked方法

    private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            //一开始肯定可以走进if语句块
            mFrameScheduled = true;
            if (USE_VSYNC) {
                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);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    一开始肯定可以走进if语句块,而下面代码则要么直接调用 scheduleVsyncLocked() 方法,要么通过handler走 scheduleVsyncLocked() 方法,所以我们还是要看 scheduleVsyncLocked() 方法

    private void scheduleVsyncLocked() {
        mDisplayEventReceiver.scheduleVsync();
    }
    
    • 1
    • 2
    • 3

    这里调用了一个鬼mDisplayEventReceiver的scheduleVsync方法,而mDisplayEventReceiver是类 FrameDisplayEventReceiver 的实例,而scheduleVsync方法是类 FrameDisplayEventReceiver 的父类 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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    指向了native方法,我们只能看下mReceiverPtr是啥了。

    private long mReceiverPtr;
    
    public DisplayEventReceiver(Looper looper, int vsyncSource) {
        ...
        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,vsyncSource);
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    调用了native的init方法,传入了一个DisplayEventReceiver的软引用,传入了自己,那么理论上这个类应该有来自native的回调,通过看注释我们知道有下面两个方法被navive对象调用

     // Called from native code.
        @SuppressWarnings("unused")
    private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
        onVsync(timestampNanos, builtInDisplayId, frame);
    }
    
    // Called from native code.
    @SuppressWarnings("unused")
    private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
        onHotplug(timestampNanos, builtInDisplayId, connected);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    而根据之前我们调用的方法名判断,应该是回掉dispatchVsync方法,这个方法里调用了onVsync方法,而刚好FrameDisplayEventReceiver类重写了这个方法,我们回到FrameDisplayEventReceiver类看下它的onVsync方法

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里通过Handler将自己作为一个Runnable对象加入到了队列中。我们再看下他的run方法

    public void run() {
        mHavePendingVsync = false;
        doFrame(mTimestampNanos, mFrame);
    }
    
    • 1
    • 2
    • 3
    • 4

    调用了Choreographer的doFrame方法

    void doFrame(long frameTimeNanos, int frame) {
        ...
        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);
        }
       ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    我们注意到这里有个 CALLBACK_ANIMATION 类型,而之前我们在Choreographer的 postFrameCallbackDelayed 方法传入过

    public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
        postCallbackDelayedInternal(CALLBACK_ANIMATION,
                                    callback, FRAME_CALLBACK_TOKEN, delayMillis);
    }
    
    • 1
    • 2
    • 3
    • 4

    所以我么看下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;
            if (callbackType == Choreographer.CALLBACK_COMMIT) {
                ...
            }
        }
        try {
            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);
            }
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    这里主要是调用了CallbackRecord的run方法,我们进去看一下

    public void run(long frameTimeNanos) {
        if (token == FRAME_CALLBACK_TOKEN) {
            //走这里,我们之前赋值token为FRAME_CALLBACK_TOKEN
            ((FrameCallback)action).doFrame(frameTimeNanos);
        } else {
            ((Runnable)action).run();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    由于我们之前传入的token为FRAME_CALLBACK_TOKEN所以会走(FrameCallback)action的doFrame方法,大家应该还记得我们的action就是我们AnimationHandler的之前传入的mFrameCallback对象吧,我们再会看一下,这个调用在AnimationHandler#addAnimationFrameCallback 方法里

    public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
        if (mAnimationCallbacks.size() == 0) {
            getProvider().postFrameCallback(mFrameCallback);
        }
        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);
        }
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们去研究下mFrameCallback对象的doFrame方法

    private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime());
            if (mAnimationCallbacks.size() > 0) {
                getProvider().postFrameCallback(this);
            }
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    先是调用doAnimationFrame方法更新动画,然后再次调用postFrameCallback方法,这样就形成了动画的连续,每一帧都会调用一次doAnimationFrame方法更新动画,我们看下doAnimationFrame方法

    private void doAnimationFrame(long frameTime) {
        long currentTime = SystemClock.uptimeMillis();
        final int size = mAnimationCallbacks.size();
        for (int i = 0; i < size; i++) {
            //之前在addAnimationFrameCallback方法里添加的
            final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
            if (callback == null) {
                continue;
            }
            if (isCallbackDue(callback, currentTime)) {
                //这里调用doAnimationFrame方法
                callback.doAnimationFrame(frameTime);
                if (mCommitCallbacks.contains(callback)) {
                    getProvider().postCommitCallback(new Runnable() {
                        @Override
                        public void run() {
                            commitAnimationFrame(callback, getProvider().getFrameTime());
                        }
                    });
                }
            }
        }
        //清空callback
        cleanUpList();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    我们之前在addAnimationFrameCallback方法里添加的AnimationFrameCallback对象(其实就是ObjectAnimator的实例),在这里调用了它的doAnimationFrame方法,由于这个AnimationFrameCallback对象是ObjectAnimator的实例,而AnimationFrameCallback的父类ValueAnimator实现了doAnimationFrame方法

    public final boolean doAnimationFrame(long frameTime) {
        if (mStartTime < 0) {
            // 第一帧。如果存在启动延迟,则在此帧之后将开始启动延迟倒计时。
            mStartTime = mReversing ? frameTime : frameTime + (long) (mStartDelay * sDurationScale);
        }
    
        // 处理 pause/resume
        if (mPaused) {
            //如果暂停状态,移除callback
            mPauseTime = frameTime;
            removeAnimationCallback();
            return false;
        } else if (mResumed) {
            mResumed = false;
            if (mPauseTime > 0) {
                //动画暂停持续时间的偏移量
                mStartTime += (frameTime - mPauseTime);
            }
        }
    
        if (!mRunning) {
           ...
        }
        mLastFrameTime = frameTime;
        final long currentTime = Math.max(frameTime, mStartTime);
        //关键点在animateBasedOnTime这里
        boolean finished = animateBasedOnTime(currentTime);
    
        if (finished) {
            //如果结束了,关闭动画
            endAnimation();
        }
        return finished;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    我们看下需要注意的animateBasedOnTime方法

    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;
            }
            //计算Fraction
            mOverallFraction = clampFraction(fraction);
            float currentIterationFraction = getCurrentIterationFraction(
                mOverallFraction, mReversing);
            //这里更新每一帧的动画值
            animateValue(currentIterationFraction);
        }
        return done;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    animateValue 方法更新每一帧的动画值,这里要注意ObjectAnimator覆写了这个方法,所以我们要看ObjectAnimator类的animateValue方法

    @Override
    void animateValue(float fraction) {
        final Object target = getTarget();
        if (mTarget != null && target == null) {
            ...
        }
        //此处会调用AnimatorUpdateListener的onAnimationUpdate方法
        super.animateValue(fraction);
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            //注意这里
            mValues[i].setAnimatedValue(target);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这里调用了mValues数组每个对象的setAnimatedValue方法,而mValues数组的对象为FloatPropertyValuesHolder的实例,我们看下FloatPropertyValuesHolder的setAnimatedValue方法

    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;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    这里有多个分支,我们无法判断他是走了哪里,但看走后一个分支可以知道他是通过反射调用了方法修改值。

    我们再回到 ValueAnimator#start 方法,

    private void start(boolean playBackwards) {
        ...
        // 在调用start()时重置mLastFrameTime,以便如果动画正在运行,则调用start())会将动画置于开始了但尚未到达的第一帧阶段。
        mLastFrameTime = -1;
        mFirstFrameTime = -1;
        mStartTime = -1;
        //关键点1
        addAnimationCallback(0);
        if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
            // 如果没有开始延迟,请初始化动画并立即通知开始侦听器,以与先前的行为保持一致。否则,将其推迟到开始延迟后的第一帧。
            //关键点2
            startAnimation();
            if (mSeekFraction == -1) {
                // 关键点3
                setCurrentPlayTime(0);
            } else {
                setCurrentFraction(mSeekFraction);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    它里面有3个关键的地方,接下来我们来看关键点2 ValueAnimator#startAnimation 方法

    startAnimation

    private void startAnimation() {
        ...
        mAnimationEndRequested = false;
        //初始化动画
        initAnimation();
        mRunning = true;
        if (mSeekFraction >= 0) {
            mOverallFraction = mSeekFraction;
        } else {
            mOverallFraction = 0f;
        }
        if (mListeners != null) {
            //通知观察者动画开始
            notifyStartListeners();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    除了 initAnimation() 方法,别的没有什么东西,我们去看下它

    void initAnimation() {
        if (!mInitialized) {
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].init();
            }
            mInitialized = true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    好像只有mValues[i].init() 方法有点价值,我们知道 mValues 是 FloatPropertyValuesHolder 类型的数组,而init方法是它的父类 PropertyValuesHolder 的方法,我们来看下

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    好像看下来也没啥东西,我们再回头看下,其实我们一直看的都是 ValueAnimator的方法,但我们实际使用的是它的子类 ObjectAnimator ,而 ObjectAnimator 覆写了 initAnimation 方法

    我们再去看一下

    void initAnimation() {
        if (!mInitialized) {
            final Object target = getTarget();
            if (target != null) {
                final int numValues = mValues.length;
                for (int i = 0; i < numValues; ++i) {
                    //初始化setter和getter
                    mValues[i].setupSetterAndGetter(target);
                }
            }
            super.initAnimation();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里我们似乎看到了setAnimatedValue 方法里的 的各个 setter 的赋值了,我们进去看下

    void setupSetterAndGetter(Object target) {
        if (mProperty != null) {
           ...
        }
        // We can't just say 'else' here because the catch statement sets mProperty to null.
        if (mProperty == null) {
            Class targetClass = target.getClass();
            if (mSetter == null) {
                //初始化setter
                setupSetter(targetClass);
            }
            List<Keyframe> keyframes = mKeyframes.getKeyframes();
            int keyframeCount = keyframes == null ? 0 : keyframes.size();
            for (int i = 0; i < keyframeCount; i++) {
                Keyframe kf = keyframes.get(i);
                if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                    if (mGetter == null) {
                        //初始化getter
                        setupGetter(targetClass);
                        if (mGetter == null) {
                            // Already logged the error - just return to avoid NPE
                            return;
                        }
                    }
                    ...
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    我们再看 setupSetter 方法

    void setupSetter(Class targetClass) {
        //mConverter应该为null,在ofFloat时不会赋值,这里应该是mValueType=Float.class
        Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    就在看setupSetterOrGetter 方法吧

    private Method setupSetterOrGetter(Class targetClass,
                                       HashMap<Class, HashMap<String, Method>> propertyMapMap,
                                       String prefix, Class valueType) {
        Method setterOrGetter = null;
        synchronized(propertyMapMap) {
           //获取targetClass对应的map
            HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
            boolean wasInMap = false;
            if (propertyMap != null) {
                wasInMap = propertyMap.containsKey(mPropertyName);
                if (wasInMap) {
                    setterOrGetter = propertyMap.get(mPropertyName);
                }
            }
            
            if (!wasInMap) {
                //第一次肯定找不到,进入方法块
                //获取mPropertyName对应的setter或getter方法
                setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
                if (propertyMap == null) {
                    //创建targetClass对应的map,并缓存
                    propertyMap = new HashMap<String, Method>();
                    propertyMapMap.put(targetClass, propertyMap);
                }
                //混存setter或getter方法
                propertyMap.put(mPropertyName, setterOrGetter);
            }
        }
        return setterOrGetter;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    看来 getPropertyFunction才是真正 获取mPropertyName对应的setter或getter方法的方法

    private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
        // TODO: faster implementation...
        Method returnVal = null;
        //根据prefix组装getter或setter方法名
        String methodName = getMethodName(prefix, mPropertyName);
        Class args[] = null;
        //此时的valueType应该为float.class
        if (valueType == null) {
            ...
        } else {
            args = new Class[1];
            Class typeVariants[];
            if (valueType.equals(Float.class)) {
                ...
            } else {
                typeVariants = new Class[1];
                typeVariants[0] = valueType;
            }
            for (Class typeVariant : typeVariants) {
                args[0] = typeVariant;
                try {
                    //反射获取getter或setter方法
                    returnVal = targetClass.getMethod(methodName, args);
                    if (mConverter == null) {
                        // change the value type to suit
                        mValueType = typeVariant;
                    }
                    return returnVal;
                } catch (NoSuchMethodException e) {
                    // Swallow the error and keep trying other variants
                }
            }
            // If we got here, then no appropriate function was found
        }
    
        if (returnVal == null) {
            ...
        }
    
        return returnVal;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    通过上面一系列调用我们可以看到,我们初始化了mSetter,是属性名的setter方法Method的引用,这里就跟setAnimatedValue 对应起来了,setAnimatedValue 方法可以用反射修改target的值

    setCurrentFraction()方法

    最后我们来看setCurrentPlayTime(0)方法

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

    走后其实还是走到了 setCurrentFraction 方法

    public void setCurrentFraction(float fraction) {
        initAnimation();
        //修正fraction在0-mRepeatCount + 1之间,如果不是无线循环的话
        fraction = clampFraction(fraction);
        mStartTimeCommitted = true; 
        ...
        final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
        //更新属性值
        animateValue(currentIterationFraction);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    setCurrentFraction 最后调用了animateValue方法,这里应该是设置属性值为初始值

    最后贴一张别人画的流程图

    // Swallow the error and keep trying other variants
            }
        }
        // If we got here, then no appropriate function was found
    }
    
    if (returnVal == null) {
        ...
    }
    
    return returnVal;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    }

    
    通过上面一系列调用我们可以看到,我们初始化了mSetter,是属性名的setter方法Method的引用,这里就跟setAnimatedValue 对应起来了,setAnimatedValue 方法可以用反射修改target的值
    
    ### setCurrentFraction()方法
    
    最后我们来看setCurrentPlayTime(0)方法
    
    ~~~java
    public void setCurrentPlayTime(long playTime) {
        float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
        setCurrentFraction(fraction);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    走后其实还是走到了 setCurrentFraction 方法

    public void setCurrentFraction(float fraction) {
        initAnimation();
        //修正fraction在0-mRepeatCount + 1之间,如果不是无线循环的话
        fraction = clampFraction(fraction);
        mStartTimeCommitted = true; 
        ...
        final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
        //更新属性值
        animateValue(currentIterationFraction);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    setCurrentFraction 最后调用了animateValue方法,这里应该是设置属性值为初始值

    最后贴一张别人画的流程图

    请添加图片描述

  • 相关阅读:
    vue form表单验证
    最好的RabbitMQ新手入门学习笔记,我们一起来学习
    Selenium最新版谷歌浏览器驱动的下载及使用
    java项目-第99期基于spring+springmvc+hibernate的在线问卷答题系统-计算机毕业设计
    认识弹性盒子flex
    3分钟看懂设计模式01:策略模式
    【数据结构】栈和队列的实现(C语言)
    uni-app使用echarts图表给图表添加点击事件/uni-app 解决echarts在h5中 tooltips及部分功能失效问题:
    Pytorch,矩阵求和维度变化解析
    用孙子兵法的智慧指导数据安全工作
  • 原文地址:https://blog.csdn.net/qq_19269585/article/details/125465850