动画
本篇记录属性动画执行的原理,本来想通过查看动画相关的源码了解动画执行的原理,没想到后面涉及的东西会越来越多
通过阅读动画相关源码你会了解一下知识:
屏幕刷新原理、Choreographer、VSync,我是看完源码后又看了 胡飞洋 Android屏幕刷新机制—VSync、Choreographer 才大概理解的,还涉及到插值器、估值器。
属性动画
首先ObjectAnimator继承自ValueAnimator,而ValueAnimator也是对动画每个时间点上值处理的关键类。
其大概原理就是 通过ofInt、ofFloat、ofArgb等将属性以及对应的值保存到PropertyValuesHolder中,然后PropertyValuesHolder通过反射将属性值注入到target中,等接收到 VSync 信号,刷新屏幕,就会通过注入的属性值改变 target,形成动画。
从ObjectAnimator的start方法进入会走到ValueAnimator的start方法中
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
} else {
this.mPlayingBackwards = playBackwards;
this.mCurrentIteration = 0;
this.mPlayingState = 0;
this.mStarted = true;
this.mStartedDelay = false;
ValueAnimator.AnimationHandler animationHandler = this.getOrCreateAnimationHandler();
animationHandler.mPendingAnimations.add(this);
if (this.mStartDelay == 0L) {
this.setCurrentPlayTime(0L);
this.mPlayingState = 0;
this.mRunning = true;
this.notifyStartListeners();
}
animationHandler.start();
}
}
从ValueAnimator.AnimationHandler的start方法进入我们即将就会看到Android屏幕刷新的关键类Choreographer
private void scheduleAnimation() {
if (!this.mAnimationScheduled) {
this.mChoreographer.postCallback(1, this, (Object)null);
this.mAnimationScheduled = true;
}
}
这里将ValueAnimator.AnimationHandler作为参数传入,再往下
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进入DisplayEventReceiver的nativeScheduleVsync方法,注册一个VSync接收垂直同步信号的回调
private void scheduleFrameLocked(long now) {
if (!this.mFrameScheduled) {
this.mFrameScheduled = true;
if (USE_VSYNC) {
if (this.isRunningOnLooperThreadLocked()) {
//如果在当前线程,立即绘制
this.scheduleVsyncLocked();
} else {
//否则同步到当前线程
Message msg = this.mHandler.obtainMessage(1);
msg.setAsynchronous(true);
this.mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
//直接绘制
long nextFrameTime = Math.max(this.mLastFrameTimeNanos / 1000000L + sFrameDelay, now);
Message msg = this.mHandler.obtainMessage(0);
msg.setAsynchronous(true);
this.mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
最后会调用doFrame方法中的doCallbacks,最后获取差值器的值,这个值是0到1间的一个float数,意思是整个动画进程的时间百分比,并通过插值器改变当前帧的值,注入target。
补间动画
补间动画是通过 刷新view,view调用onDraw实现,
Android动画之补间动画TweenAnimation