Android6.0 WMS(六) WMS动画管理

2019-04-04 23:16

Android6.0 WMS(六) WMS动画管

Android的应用启动时,或者切换Activity时都会以动画的方式显示前后两屏的切换过程。动画的原理很简单,把一帧一帧的图像按一定时间间隔显示出来就完成了。

动画的绘制需要定时驱动,通常的做法是启动一个定时消息,每隔一定时间发一个消息,收到消息后输出一帧画面。Android支持VSync信号后,动画的驱动就有VSync信号承担了。 窗口动画的基本元素是窗口Surface中保存的图像,通过对窗口的Surface设置不同的变换矩阵和透明度,然后强制Surface刷新,就能在屏幕上显示出窗口的变化过程。

Choreographer对象初始化

我们先来看WMS中的mChoreographer 变量

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 final Choreographer mChoreographer = Choreographer.getInstance();

该变量是一个线程局部存储变量,在它的initialValue中创建了Choreographer对象并返回。这里使用线程局部存储的目录就是保证在线程中只有一个Choreographer对象。 [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 public static Choreographer getInstance() { return sThreadInstance.get(); }

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 private static final ThreadLocal sThreadInstance = new ThreadLocal() { @Override

protected Choreographer initialValue() { Looper looper = Looper.myLooper(); if (looper == null) {

throw new IllegalStateException(\ }

return new Choreographer(looper); } };

再来看下Choreographer的构造函数,这里主要是创建了FrameDisplayEventReceiver用来接受VSync信号的对象。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 private Choreographer(Looper looper) { mLooper = looper;

mHandler = new FrameHandler(looper);

mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;//接受VSync信号对象

mLastFrameTimeNanos = Long.MIN_VALUE;

mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());//计算刷新的时间间隔

mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; for (int i = 0; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new CallbackQueue(); } }

FrameDisplayEventReceiver接受VSync信号

当VSync信号过来时,最后会调用到FrameDisplayEventReceiver类的onVsync函数: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 @Override

public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { scheduleVsync(); return; }

long now = System.nanoTime(); if (timestampNanos > now) {

Log.w(TAG, \

+ \ Check that graphics HAL is generating vsync \ + \ timestampNanos = now; }

if (mHavePendingVsync) {

Log.w(TAG, \ There should only be \ + \ } else {

mHavePendingVsync = true; }

mTimestampNanos = timestampNanos; mFrame = frame;

Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true);

mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); }

这主要是发送了一个信号,而是是Runnable的那种消息。

因此我们主要看下这个类的run函数,这里就是调用了Choreographer的doFrame函数。 [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 @Override

public void run() {

mHavePendingVsync = false;

doFrame(mTimestampNanos, mFrame); }

doFrame函数

doFrame函数主要有一些VSync时间逻辑处理如果抛弃该VSync信号的话会调用scheduleVsyncLocked函数让SurfaceFlinger发送一个VSync信号,如果正常会调用4个doCallBacks函数。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void doFrame(long frameTimeNanos, int frame) { final long startNanos; synchronized (mLock) { ......

long intendedFrameTimeNanos = frameTimeNanos; startNanos = System.nanoTime();

final long jitterNanos = startNanos - frameTimeNanos; if (jitterNanos >= mFrameIntervalNanos) {

final long skippedFrames = jitterNanos / mFrameIntervalNanos; final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; frameTimeNanos = startNanos - lastFrameOffset; }

if (frameTimeNanos < mLastFrameTimeNanos) { if (DEBUG_JANK) {

Log.d(TAG, \ May be due to a \ + \ Waiting for next vsync.\ }

scheduleVsyncLocked();//让SurfaceFlinger立马发送一个VSync信号 return; }

mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos); mFrameScheduled = false;

mLastFrameTimeNanos = frameTimeNanos; }

try {

Trace.traceBegin(Trace.TRACE_TAG_VIEW, \

mFrameInfo.markInputHandlingStart();

doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);//按键相关

mFrameInfo.markAnimationsStart();

doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);//动画相关

mFrameInfo.markPerformTraversalsStart();

doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);//power相关

doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); } finally {

Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }

doCallbacks函数,我们首先会检查当前这个CallBackType是否有对应的CallBack回调,如果没有直接return,如果有的话会调用其回调的run函数。 [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 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) {//没有对应CallBack回调 return; }

mCallbacksRunning = true;

// safe by ensuring the commit time is always at least one frame behind. if (callbackType == Choreographer.CALLBACK_COMMIT) { final long jitterNanos = now - frameTimeNanos;

Trace.traceCounter(Trace.TRACE_TAG_VIEW, \ if (jitterNanos >= 2 * mFrameIntervalNanos) {

final long lastFrameOffset = jitterNanos % mFrameIntervalNanos + mFrameIntervalNanos; if (DEBUG_JANK) {

mDebugPrintNextFrameTimeDelta = true; }

frameTimeNanos = now - lastFrameOffset; mLastFrameTimeNanos = frameTimeNanos; } } } try {

for (CallbackRecord c = callbacks; c != null; c = c.next) {

c.run(frameTimeNanos);//调用回调run函数 } } ...... }

这也就意味着当你没有CallBackType对应的回调,每次VSync信号过来到doFrame函数再到doCallBacks函数都是没有意义的。

WMS启动动画

那我们下面看在哪里把CallBackType对应的回调加入了,这里我们只关注动画相关的。 上面我们说到VSync会不断的发送,每秒60多次,但是动画不会不停的播放,就是这个CallBackType对应的回调没有。哪动画的启动和结束也就是受这个影响,而就是在WMS中调用scheduleAnimationLocked函数发起的动画启动。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void scheduleAnimationLocked() { if (!mAnimationScheduled) {

mAnimationScheduled = true;

mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback); } }

这里就是调用Choreographer设置CallBackType,相关的回调。这里我们的callbackType是CALLBACK_ANIMATION

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 public void postFrameCallback(FrameCallback callback) { postFrameCallbackDelayed(callback, 0); }

public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { if (callback == null) {

throw new IllegalArgumentException(\ }

postCallbackDelayedInternal(CALLBACK_ANIMATION,

callback, FRAME_CALLBACK_TOKEN, delayMillis); }

我们最后看postCallbackDelayedInternal函数,就是在mCallBackQueues对应的CallBackType中增加相应的回调。这里也就是前面在WMS的scheduleAnimationLocked的参数mAnimator.mAnimationFrameCallback就是回调。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { synchronized (mLock) {

final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis;


Android6.0 WMS(六) WMS动画管理.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:旅游资源 读书笔记

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: