ValueAnimation 是如何刷新的
背景
之前,技术分享讲过ValueAnimation底层源码。但是,没有提到,Animation的更新。此篇文章,聚焦于ValueAnimation start方法开始,到Choreographer的响应回调。
ValueAnimator部分
ValueAnimator.start()
从思维逻辑上,start方法是动画启动的入口,那绘制应该也从这里开始寻找
//ValueAnimator
@Override
public void start() {
start(false);
}
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) {
// 计算当前迭代的分数。
float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
mSeekFraction = 1 - fraction;
} else {
mSeekFraction = 1 + mRepeatCount - mSeekFraction;
}
}
mStarted = true;
mPaused = false;
mRunning = false;
mAnimationEndRequested = false;
// 当start()被调用时,重置mLastFrameTime,这样如果动画正在运行,
// 调用start()将把动画放到已经开始但尚未到达的第一帧阶段。
mLastFrameTime = -1;
mFirstFrameTime = -1;
mStartTime = -1;
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
// 如果没有启动延迟,初始化动画并立即通知启动监听器,
// 以与前面的行为保持一致。否则,将此延迟到开始延迟后的第一帧。
startAnimation();
if (mSeekFraction == -1) {
// 无seek, 0时开始。注意,我们没有使用分数0的原因是,对于持续时间为0的动画,
// 我们希望与前n的行为保持一致:立即跳到最终值。
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
需求要注意的是,在startAnimation
方法中进行数值的初始化,和Linstener
的调用。但是不在本篇的范围内,不做分析。其中重点是addAnimationCallback
方法。
//ValueAnimator
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
public AnimationHandler getAnimationHandler() {
return mAnimationHandler != null ? mAnimationHandler : AnimationHandler.getInstance();
}
AnimationHandler
可以看到,addAnimationCallback
方法,最终调用到的是AnimationHandler
的addAnimationFrameCallback
方法。
//AnimationHandler
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
//如果之前没有动画要展示,就找provider启动动画循环(假循环)
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
//之前不存在,就往进加
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
注释很清楚,我们应该往getProvider().postFrameCallback
里看。
//AnimationHandler
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {
final Choreographer mChoreographer = Choreographer.getInstance();
//就是这里
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
@Override
public void postCommitCallback(Runnable runnable) {
mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
}
@Override
public long getFrameTime() {
return mChoreographer.getFrameTime();
}
@Override
public long getFrameDelay() {
return Choreographer.getFrameDelay();
}
@Override
public void setFrameDelay(long delay) {
Choreographer.setFrameDelay(delay);
}
}
我们可以看到,就是往Choreographer
里面塞回调。这个Choreographer
我们后期会讲到,我们目前只需要知道,当Choreographer
收到Vsync
后,会依次回调Callback就好了,其中调用onFrame
方法。
这里塞的是什么呢?mFrameCallback
//AnimationHandler
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
doAnimationFrame
我们看到,会调用,doAnimationFrame
//AnimationHandler
private void doAnimationFrame(