Android animation/Animator 源码分析

Animationandroid.view.animation.Animation)对象 我们使用的时候,一般是用这样的形式:View.startAnimation(a);

那么就来看看View中的startAnimation()方法。

1.View.startAnimation(Animation)

先是调用View.setAnimation(Animation)方法给自己设置一个Animation对象,这个对象是View类中的一个名为mCurrentAnimation的成员变量。

然后它调用invalidate()来重绘自己。

我想,既然setAnimation()了,那么它要用的时候,肯定要getAnimation(),找到这个方法在哪里调用就好了。于是通过搜索,在View.draw(Canvas, ViewGroup, long)方法中发现了它的调用,代码片段如下:

2.View.draw(Canvas, ViewGroup, long)

其中调用了View.drawAnimation()方法。

 3.View.drawAnimation(ViewGroup, long, Animation, boolean)代码片段如下:

其中调用了Animation.getTransformation()方法。

4.Animation.getTransformation(long, Transformation, float)

该方法直接调用了两个参数Animation.getTransformation()方法。

5.Animation.getTransformation(long, Transformation)

该方法先将参数currentTime处理成一个float表示当前动画进度,比如说,一个2000ms的动画,已经执行了1000ms了,那么进度就是0.5或者说50%。

然后将进度值传入插值器(Interpolator)得到新的进度值,前者是均匀的,随着时间是一个直线的线性关系,而通过插值器计算后得到的是一个曲线的关系。

然后将新的进度值和Transformation对象传入applyTranformation()方法中。

6.Animation.applyTransformation(float, Transformation)

Animation的applyTransformation()方法是空实现,具体实现它的是Animation的四个子类,而该方法正是真正的处理动画变化的过程。分别看下四个子类的applyTransformation()的实现。

ScaleAnimation

AlphaAnimation

RotateAnimation

TranslateAnimation

可见applyTransformation()方法就是动画具体的实现,系统会以一个比较高的频率来调用这个方法,一般情况下60FPS,是一个非常流畅的画面了,也就是16ms,这个和Choreographer(android.view.Choreographer)类的原理有关。

6.Choreographer.doFrame()

它调用了三次doCallbacks()方法,暂且不说这个方法是干什么的,但从它的第一个参数可以看到分别是输入(INPUT),动画(ANIMATION),遍历(TRAVERSAL)

于是,我先是看了下这三个常量的意义。下图所示:

显然,注释是说:输入事件最先处理,然后处理动画,最后才处理view的布局和绘制。接下来我们看看Choreographer.doCallbacks()里面做了什么。

7.Choreographer.doCallbacks(int, long)

这个方法的操作非常统一,有三种不同类型的操作(输入,动画,遍历),但在这里却看不见这些具体事件的痕迹,这里我们不得不分析一下mCallbackQueues这个成员变量了。

mCallbackQueues是一个CallbackQueue对象数组。而它的下标,其意义并不是指元素1,元素2,元素3……而是指类型,请看上面doCallbacks()的代码,参数callbackType传给了mCallbackQueues[callbackType]中,而callbackType是什么呢?

其实就是前面说到的三个常量,CALLBACK_INPUTCALLBACK_ANIMATIONCALLBACK_TRAVERVAL

那么只需要根据不同的callbackType,就可以从这个数组里面取出不同类型的CallbackQueue对象来。

那么CallbackQueue又是什么呢?

CallbackQueueChoreographer的一个内部类,其中我认为有两个很重要的方法,分别是:extractDueCallbacksLocked(long)addCallbackLocked(long, Object, Object)

先说addCallbackLocked(long, Object, Object)

1.CallbackQueue.addCallbackLocked(long, Object, Object)

首先它通过一个内部方法构建了一个CallbackRecord对象,然后后面的if判断和while循环,大致上是将参数中的对象链接在CallbackRecord的尾部。其实CallbackRecord就是一个链表结构的对象。

2.CallbackQueue.extractDueCallbacksLocked(long)

这个方法是根据当前的时间,选出执行链表中与该时间最近的一个操作来处理,实际上,我们可以通俗的理解为“跳帧”。

想象一下,如果主线程运行的非常快速,非常流畅,每一步都能在10ms内准时运行到,那么我们的执行链表中的元素始终只有一个。

如果主线程中做了耗时操作,那么各种事件一直在往各自的链表中添加,但是当主线程有空来执行的时候,发现链表已经那么多积累的过期的事件了,那么就直接选择最后一个来执行,那么界面上看起来,就是卡顿了一下。

ObjectAnimator.start()方法实际上是辗转几次调用了ValueAnimator的start()方法,ValueAnimator.start()又调用了一个临时变量animationHandler.start()。

animationHandler实际上是一个Runnable,其中start()方法调用了scheduleAnimation()。

而这个方法:

调用了postCallback()方法。

将this(Runnable)post之后,实际上肯定就是要执行Runnable.run()方法

run()方法中又调用了doAnimationFrame()方法。这个方法具体的实现了动画的某一帧的过程,然后再次调用了scheduleAnimation()方法。

就相当于postDelayed(this, 16)这种方式了。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

滚动至顶部