Android提供了属性动画这个强大的框架来帮助开发者实现比较复杂的动画。
先引出几个关键的类:ObjectAnimator,ValueAnimator,PropertyValuesHolder和Choreographer。我们从ObjectAnimator的使用方式开始分析:
ObjectAnimator.ofInt(mButton, width, 500).setDuration(5000).start()。先看ofint方法,其实就是返回了一个确定了作用对象,作用属性和属性数值的objectanimator对象。执行这个动画是start开始的。ObjectAnimator直接调用的父类ValueAnimator的super.start()。
最后调用了animationHandler.start();这里的animationHandler不是一个handler而是一个Runnable,重点来了,看这个AnimationHandler中有一个mChoreographer,这个是控制器哦。Start之后调用的是
这个方法什么作用呢?它是向choreographer中post了一个回调,并将自己传过去了,好了,剩下的工作就在choreographer中进行,先来看看这个类的结构,重要的东西有一个threadlocal的instance,看来是一个单例模式,并且应该是能支持到多线程操作的。(PS后面会有针对当前是否为UI thread的判断处理)还有FrameHandler(有handler肯定就有looper啊,没错这里也是有的,这个handler主要就是用来处理一些msg的,以及控制执行此帧的时间间隔)和一个mCallbackQueues(很明显是一个callback的队列)。
继续来看看postcallback以后的工作,会调到下面这个方法。
前面分支判断之后最终都会调用到下面这个方法,而在这个方法里面就一个难点,scheduleVsyncLocked(),这个东西是android 4.1之后加入的关键技术vsync timing和triple buffer,用于提高UI的流畅度。这个就是显示技术上的优化,不影响动画过程的分析。我们继续看普通的情况,特就是向handler中send了一个msg_do_frame的消息。
现在回过头去看看animationHandler的run中做了一些什么事情,
这一段代码很多,前面都是一些判断,有延时的就绪的结束的等等,但是重点是anim.doAnimationFrame(frameTime)和最后判断启动下一帧的过程。下一帧就是重复之前分析的过程。下面来看看doAnimationFrame这是执行设置属性变化的地方。doAnimationFrame最终会调用到animateValue,这里面的堆栈调用一目了然就不详细说了,这个方法在valueanimator中有一个,但是在子类objectanimator中重写了这个方法并同时执行了super的方法。放在一起看比较清楚。
mValues这个是父类中的成员变量,它就是之前设置的属性值的容器PropertyValuesHolder,mValues[i].calculateValue(fraction);这个方法中是根据最终属性值和进度计算当前属性值的过程(里面还会涉及到一个Interpolator插值器,这个东西一控制你当前动画执行的效果),mValues[i].setAnimatedValue(mTarget);这个显然就是使得属性值在target对象上生效的过程咯。后面的就不详细说了,其实就是使用放射机制对目标对象指向set属性和get属性(所以啊,这里对目标对象执行对应属性的变化必须确保改变的属性有set和get方法,并且与你设想的效果要是一致的,具体的使用可以看看文章开头推荐的那个帖子 )。
整个属性动画的执行过程就是如此,没有什么难的,但是给大家引出了一个难点,就是vsync timing和triple buffer的显示机制,这个可以参考 http://blog.csdn.net/innost/article/details/8272867 这个帖子的分析,说得很透彻。
网上已经有很多帖子为大家介绍属性动画的使用,先给大家推荐一篇写的比较好的。http://
www.2cto.com/kf/201401/270169.html
本文不讲使用方法,是从源码的角度来分析属性动画框架的工作原理。先引出几个关键的类:ObjectAnimator,ValueAnimator,PropertyValuesHolder和Choreographer。我们从ObjectAnimator的使用方式开始分析:
ObjectAnimator.ofInt(mButton, width, 500).setDuration(5000).start()。先看ofint方法,其实就是返回了一个确定了作用对象,作用属性和属性数值的objectanimator对象。执行这个动画是start开始的。ObjectAnimator直接调用的父类ValueAnimator的super.start()。
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
mPlayingBackwards = playBackwards;
mCurrentIteration = 0;
mPlayingState = STOPPED;
mStarted = true;
mStartedDelay = false;
AnimationHandler animationHandler = getOrCreateAnimationHandler();
animationHandler.mPendingAnimations.add(this);
if (mStartDelay == 0) {
// This sets the initial value of the animation, prior to actually starting it running
setCurrentPlayTime(0);
mPlayingState = STOPPED;
mRunning = true;
notifyStartListeners();
}
animationHandler.start();
}
最后调用了animationHandler.start();这里的animationHandler不是一个handler而是一个Runnable,重点来了,看这个AnimationHandler中有一个mChoreographer,这个是控制器哦。Start之后调用的是
private void scheduleAnimation() {
if (!mAnimationScheduled) {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
mAnimationScheduled = true;
}
}
这个方法什么作用呢?它是向choreographer中post了一个回调,并将自己传过去了,好了,剩下的工作就在choreographer中进行,先来看看这个类的结构,重要的东西有一个threadlocal的instance,看来是一个单例模式,并且应该是能支持到多线程操作的。(PS后面会有针对当前是否为UI thread的判断处理)还有FrameHandler(有handler肯定就有looper啊,没错这里也是有的,这个handler主要就是用来处理一些msg的,以及控制执行此帧的时间间隔)和一个mCallbackQueues(很明显是一个callback的队列)。
继续来看看postcallback以后的工作,会调到下面这个方法。
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG) {
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);
//这里就可以看到了,当valueanimator设置回调时都会保存在这个队列当中,等待需要处理时再从里面取出来
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);
//执行do frame是有间隔的哟,有一个默认的间隔是常量DEFAULT_FRAME_DELAY = 10
}
}
}
前面分支判断之后最终都会调用到下面这个方法,而在这个方法里面就一个难点,scheduleVsyncLocked(),这个东西是android 4.1之后加入的关键技术vsync timing和triple buffer,用于提高UI的流畅度。这个就是显示技术上的优化,不影响动画过程的分析。我们继续看普通的情况,特就是向handler中send了一个msg_do_frame的消息。
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG) {
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 / NANOS_PER_MS sFrameDelay, now);
if (DEBUG) {
Log.d(TAG, "Scheduling next frame in " (nextFrameTime - now) " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
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 doFrame(long frameTimeNanos, int frame) {
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
}
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible
// for earlier processing phases in a frame to post callbacks that should run
// in a following phase, such as an input event that causes an animation to start.
final long now = SystemClock.uptimeMillis();
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
}
try {
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG) {
Log.d(TAG, "RunCallback: type=" callbackType
", action=" c.action ", token=" c.token
", latencyMillis=" (SystemClock.uptimeMillis() - c.dueTime));
}
c.run(frameTimeNanos);
//执行到这里终于转到正题上来了,执行了前面animationHandler的run方法。
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
}
}
现在回过头去看看animationHandler的run中做了一些什么事情,
public void run() {
mAnimationScheduled = false;
doAnimationFrame(mChoreographer.getFrameTime());
}
private void doAnimationFrame(long frameTime) {
// mPendingAnimations holds any animations that have requested to be started
// We're going to clear mPendingAnimations, but starting animation may
// cause more to be added to the pending list (for example, if one animation
// starting triggers another starting). So we loop until mPendingAnimations
// is empty.
while (mPendingAnimations.size() > 0) {
ArrayList<ValueAnimator> pendingCopy =
(ArrayList<ValueAnimator>) mPendingAnimations.clone();
mPendingAnimations.clear();
int count = pendingCopy.size();
for (int i = 0; i < count; i) {
ValueAnimator anim = pendingCopy.get(i);
// If the animation has a startDelay, place it on the delayed list
if (anim.mStartDelay == 0) {
anim.startAnimation(this);
} else {
mDelayedAnims.add(anim);
}
}
}
// Next, process animations currently sitting on the delayed queue, adding
// them to the active animations if they are ready
int numDelayedAnims = mDelayedAnims.size();
for (int i = 0; i < numDelayedAnims; i) {
ValueAnimator anim = mDelayedAnims.get(i);
if (anim.delayedAnimationFrame(frameTime)) {
mReadyAnims.add(anim);
}
}
int numReadyAnims = mReadyAnims.size();
if (numReadyAnims > 0) {
for (int i = 0; i < numReadyAnims; i) {
ValueAnimator anim = mReadyAnims.get(i);
anim.startAnimation(this);
anim.mRunning = true;
mDelayedAnims.remove(anim);
}
mReadyAnims.clear();
}
// Now process all active animations. The return value from animationFrame()
// tells the handler whether it should now be ended
int numAnims = mAnimations.size();
for (int i = 0; i < numAnims; i) {
mTmpAnimations.add(mAnimations.get(i));
}
for (int i = 0; i < numAnims; i) {
ValueAnimator anim = mTmpAnimations.get(i);
if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
mEndingAnims.add(anim);
}
}
mTmpAnimations.clear();
if (mEndingAnims.size() > 0) {
for (int i = 0; i < mEndingAnims.size(); i) {
mEndingAnims.get(i).endAnimation(this);
}
mEndingAnims.clear();
}
// If there are still active or delayed animations, schedule a future call to
// onAnimate to process the next frame of the animations.
if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
scheduleAnimation();
}
}
这一段代码很多,前面都是一些判断,有延时的就绪的结束的等等,但是重点是anim.doAnimationFrame(frameTime)和最后判断启动下一帧的过程。下一帧就是重复之前分析的过程。下面来看看doAnimationFrame这是执行设置属性变化的地方。doAnimationFrame最终会调用到animateValue,这里面的堆栈调用一目了然就不详细说了,这个方法在valueanimator中有一个,但是在子类objectanimator中重写了这个方法并同时执行了super的方法。放在一起看比较清楚。
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);
}
}
}
void animateValue(float fraction) {
//执行的就是上述操作
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; i) {
mValues[i].setAnimatedValue(mTarget);
}
}
mValues这个是父类中的成员变量,它就是之前设置的属性值的容器PropertyValuesHolder,mValues[i].calculateValue(fraction);这个方法中是根据最终属性值和进度计算当前属性值的过程(里面还会涉及到一个Interpolator插值器,这个东西一控制你当前动画执行的效果),mValues[i].setAnimatedValue(mTarget);这个显然就是使得属性值在target对象上生效的过程咯。后面的就不详细说了,其实就是使用放射机制对目标对象指向set属性和get属性(所以啊,这里对目标对象执行对应属性的变化必须确保改变的属性有set和get方法,并且与你设想的效果要是一致的,具体的使用可以看看文章开头推荐的那个帖子 )。
整个属性动画的执行过程就是如此,没有什么难的,但是给大家引出了一个难点,就是vsync timing和triple buffer的显示机制,这个可以参考 http://blog.csdn.net/innost/article/details/8272867 这个帖子的分析,说得很透彻。
本文从源码角度深入分析Android属性动画框架的工作原理,包括ObjectAnimator、ValueAnimator等关键类的作用及交互过程。

468

被折叠的 条评论
为什么被折叠?



