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

更新时间:2024-06-12 18:07:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

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;

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函数,我们注意mFrameScheduled这个变量,这个时候赋值为true,后面就是用这个变量来控制每次VSync信号过来调用doFrame函数的时候是否要播放动画

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 private void scheduleFrameLocked(long now) { if (!mFrameScheduled) {

mFrameScheduled = true;//注意这个变量 if (USE_VSYNC) {

if (isRunningOnLooperThreadLocked()) {

scheduleVsyncLocked();//尽快让SurfaceFlinger中的EventThread发送一个VSync信号

} else {

Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true);

mHandler.sendMessageAtFrontOfQueue(msg); } } else {

final long nextFrameTime = Math.max(

mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);

if (DEBUG_FRAMES) {

Log.d(TAG, \ }

Message msg = mHandler.obtainMessage(MSG_DO_FRAME); msg.setAsynchronous(true);

mHandler.sendMessageAtTime(msg, nextFrameTime); } } }

我们再回过头来看doFrame函数,当mFrameScheduled为false时,VSync信号过来该函数直接return不会播放动画。

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

if (!mFrameScheduled) { return; // no work to do }

继续看postCallbackDelayedInternal函数中增加的回调,这个回调在WindowAnimator的构造函数中就新建了Choreographer.FrameCallback回调

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 WindowAnimator(final WindowManagerService service) { mService = service;

mContext = service.mContext; mPolicy = service.mPolicy;

mAnimationFrameCallback = new Choreographer.FrameCallback() { public void doFrame(long frameTimeNs) { synchronized (mService.mWindowMap) { mService.mAnimationScheduled = false; animateLocked(frameTimeNs); } } }; }

我们最后看回调的run函数,如果是FRAME_CALLBACK_TOKEN,就是调用回调的doFrame函数。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 private static final class CallbackRecord { public CallbackRecord next; public long dueTime;

public Object action; // Runnable or FrameCallback public Object token;

public void run(long frameTimeNanos) {

if (token == FRAME_CALLBACK_TOKEN) {

((FrameCallback)action).doFrame(frameTimeNanos); } else {

((Runnable)action).run(); } } }

播放动画

在上面doFrame函数启动动画,而动画的播放主要在WindowAnimator的animateLocked函

数。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 private void animateLocked(long frameTimeNs) { ......

boolean wasAnimating = mAnimating;

mAnimating = false;//设置mAnimating为false mAppWindowAnimating = false;

SurfaceControl.openTransaction();

SurfaceControl.setAnimationTransaction(); try {

final int numDisplays = mDisplayContentsAnimators.size(); for (int i = 0; i < numDisplays; i++) {

final int displayId = mDisplayContentsAnimators.keyAt(i); updateAppWindowsLocked(displayId); ......

// Update animations of all applications, including those // associated with exiting/removed apps updateWindowsLocked(displayId); updateWallpaperLocked(displayId);

final WindowList windows = mService.getWindowListLocked(displayId); final int N = windows.size(); for (int j = 0; j < N; j++) {

windows.get(j).mWinAnimator.prepareSurfaceLocked(true);//输出动画帧 } }

for (int i = 0; i < numDisplays; i++) {

final int displayId = mDisplayContentsAnimators.keyAt(i);

testTokenMayBeDrawnLocked(displayId);

final ScreenRotationAnimation screenRotationAnimation =

mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation; if (screenRotationAnimation != null) {

screenRotationAnimation.updateSurfacesInTransaction(); }

mAnimating mService.getDisplayContentLocked(displayId).animateDimLayers();

if (mService.mAccessibilityController != null

|= && displayId == Display.DEFAULT_DISPLAY) {

mService.mAccessibilityController.drawMagnifiedRegionBorderIfNeededLocked(); } }

if (mAnimating) {//为true,继续调用WMS的scheduleAnimationLocked播放下一帧 mService.scheduleAnimationLocked(); }

...... finally {

SurfaceControl.closeTransaction(); }

......

boolean doRequest = false; if (mBulkUpdateParams != 0) {

doRequest = mService.copyAnimToLayoutParamsLocked(); }

if (hasPendingLayoutChanges || doRequest) {

mService.requestTraversalLocked();//重新刷新UI }

if (!mAnimating && wasAnimating) { mService.requestTraversalLocked(); } }

animateLocked方法先将mAnimating 设置为false,然后调用updateWindowsLocked函数和updateWallpaperLocked函数,updateWindowsLocked这个函数会调用WindowStateAnimator类的stepAnimationLocker方法,如果动画已经显示完最后一帧,stepAnimationLocker方法将会WindowStateAnimator类的mAnimating设置为false,表示该窗口的动画已经结束。而在updateWallpaperLocked函数中会判断所有窗口的动画是否已经结束,只要有一个动画没结束,就会将winAnimator的mAnimating设置为true。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 for (int i = windows.size() - 1; i >= 0; i--) { final WindowState win = windows.get(i);

WindowStateAnimator winAnimator = win.mWinAnimator; if (winAnimator.mSurfaceControl == null) { continue; }

final int flags = win.mAttrs.flags;

if (winAnimator.mAnimating) { ......

mAnimating = true; } ......

再回到animatelocked方法,当mAnimating为true是会调用WMS的scheduleAnimationLocked方法继续显示动画,否则动画显示就结束了。

下面我们总结下动画的播放过程:需要播放动画时,先会调用WMS的scheduleAnimationLocked方法。调用这个方法后,才会接受并处理一次VSync信号,对VSync信号的处理,就是所有需要绘制的窗口根据各自动画的谁知重新调整窗口Surface的变化矩阵和透明度;如果还有窗口动画需要显示,继续调用scheduleAnimationLocked方法准备下一帧。

准备一帧动画的时间可以跨越多个VSync信号周期,但是只有收到VSync信号才能更新窗口的Surface的属性和内容,对应用而言收到VSync信号意味着SurfaceFlinger中已经把上次设置的动画数据取走了,可以安全地设置下一帧动画的属性和内容了。

窗口动画对象WindowStateAnimator

窗口对象WindowState中定义了一个类型为WindowStateAnimator的成员变量mWinAnimator,用来表示窗口的动画对象。 下面是一些成员变量

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 boolean mAnimating;//表示是否正在显示动画

boolean mLocalAnimating;//表示窗口动画是否已经初始化 Animation mAnimation;//表示窗口动画对象 boolean mAnimationIsEntrance;//

boolean mHasTransformation;//表示当前动画的mTransformation是否可用

boolean mHasLocalTransformation;//表示当前动画时一个窗口动画还是Activity动画 final Transformation mTransformation = new Transformation();//变换矩阵对象

当前正在显示的动画有两种类型,一种的窗口切换动画,一种是Activity切换动画,这里使用了mLocalAnimating和mHasLocalTransformation分别表示窗口动画的状态。

stepAnimationLocked是WindowStateAnimator类中显示动画首先调用的方法,它会初始化WindowStateAnimator对象的一些成员变量

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 boolean stepAnimationLocked(long currentTime) {

final DisplayContent displayContent = mWin.getDisplayContent(); if (displayContent != null && mService.okToDisplay()) {

if (mWin.isDrawnLw() && mAnimation != null) {//窗口准备好绘制了,窗口动画对象不为空

mHasTransformation = true;

mHasLocalTransformation = true;

if (!mLocalAnimating) {//还没有初始化窗口对象

final DisplayInfo displayInfo = displayContent.getDisplayInfo();

if (mAnimateMove) {

mAnimateMove = false;

mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),//初始化窗口对象

mAnimDw, mAnimDh); } else {

mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), displayInfo.appWidth, displayInfo.appHeight); }

mAnimDw = displayInfo.appWidth; mAnimDh = displayInfo.appHeight;

mAnimation.setStartTime(mAnimationStartTime != -1 ? mAnimationStartTime : currentTime);

mLocalAnimating = true;// 设置为true代表已经初始化窗口对象 mAnimating = true; }

if ((mAnimation != null) && mLocalAnimating) { mLastAnimationTime = currentTime;

if (stepAnimation(currentTime)) {//通过时间判断动画是否显示完毕 return true; } } }

mHasLocalTransformation = false;

if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null//没有设置窗口动画或者窗口动画结束了

&& mAppAnimator.animation != null) {

// 如果有Activity动画,将mAnimating设为true mAnimating = true;

mHasTransformation = true; mTransformation.clear(); return fwww.sm136.comalse; } else if (mHasTransformation) {

// Little trick to get through the path below to act like // we have finished an animation. mAnimating = true; } else if (isAnimating()) { mAnimating = true; }

} else if (mAnimation != null) { mAnimating = true; }

if (!mAnimating && !mLocalAnimating) { return false; }

mAnimating = false;

mKeyguardGoingAwayAnimation = false; mAnimatingMove = false; mLocalAnimating = false; ......

mHasLocalTransformation = false; ......

mTransformation.clear(); ......

return false; }

该方法的工作就是设置WindowStateAnimator对象的几个成员变量,首先调用WindowState对象的isDrawnLw来判断窗口系统的状态,只有准备好了才能显示,接着判断mAnimation是否为空,不为空代表已经设置好了动画对象。

接下来判断mLocalAnimating变量的值,为false则调用mAnimation的intialize方法来完成动画对象的初始化(主要设置动画的高度和宽度),然后将mLocalAnimating和mAnimating设为true。完成初始化后,接着调用stepAnimation方法来判断动画是否已经显示完成,没有完成返回true。

如果没有设置动画或者动画已经结束了,则还有判断窗口所在的Activity是否还存在动画,如果有,将mAnimating设置true(表示还要继续播放动画),如果同时mHasTransformation的值仍然为true,或者isAnimating方法返回true,也将mAnimating设置为true。 isAnimating会根据当前动画对象mAnimation是否为空,它的附加窗口的动画对象是否为空,以及窗口所在的Activity的动画对象是否为空等条件来判断,这表示只要有可能mAnimating就会设置为true。这样的目的尽量让动画完成显示,即使没有可显示的动画,多刷新几次不会有副作用,但如果少画了一次,屏幕上就可能留下不正确画面了。 [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 boolean isAnimating() {

return mAnimation != null

|| (mAttachedWinAnimator != null && mAttachedWinAnimator.mAnimation != null)

|| (mAppAnimator != null && mAppAnimator.isAnimating()); }

我们再看看动画的生成过程,WindowStateAnimator的prepareSurfaceLocked方法来完成计算一帧动画并显示工作:

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片 public void prepareSurfaceLocked(final boolean recoveringMemory) {

......

computeShownFrameLocked();//计算要显示的动画帧

setSurfaceBoundariesLocked(recoveringMemory);

if (mIsWallpaper && !mWin.mWallpaperVisible) { hide();//如果是壁纸窗口,隐藏

} else if (w.mAttachedHidden || !w.isOnScreen()) { hide();//如果窗口不可见,隐藏 ......

} else if (mLastLayer != mAnimLayer || mLastAlpha != mShownAlpha || mLastDsDx != mDsDx || mLastDtDx != mDtDx || mLastDsDy != mDsDy || mLastDtDy != mDtDy

|| w.mLastHScale != w.mHScale || w.mLastVScale != w.mVScale

|| mLastHidden) {//每个值是否有变化 displayed = true;

mLastAlpha = mShownAlpha; mLastLayer = mAnimLayer; mLastDsDx = mDsDx; mLastDtDx = mDtDx; mLastDsDy = mDsDy; mLastDtDy = mDtDy;

w.mLastHScale = w.mHScale; w.mLastVScale = w.mVScale;

if (mSurfaceControl != null) { try {

mSurfaceAlpha = mShownAlpha;

mSurfaceControl.setAlpha(mShownAlpha); mSurfaceLayer = mAnimLaync630.comer; mSurfaceControl.setLayer(mAnimLayer); mSurfaceControl.setMatrix(

mDsDx * w.mHScale, mDtDx * w.mVScale, mDsDy * w.mHScale, mDtDy * w.mVScale);

if (mLastHidden && mDrawState == HAS_DRAWN) { if (showSurfaceRobustlyLocked()) {//输出动画帧 mLastHidden = false; if (mIsWallpaper) {

mService.dispatchWallpaperVisibility(w, true);

}

mAnimator.setPendingLayoutChanges(w.getDisplayId(),

WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM); } else {

w.mOrientationChanging = false; } }

if (mSurfaceControl != null) { w.mToken.hasVisible = true; }

} catch (RuntimeException e) {

Slog.w(TAG, \ if (!recoveringMemory) {

mService.reclaimSomeSurfaceMemoryLocked(this, \ } } } } ...... }

该函数先调用了computeShownFrameLocked函数计算当前需要显示的动画帧数据,mAnimLayer表示窗口的Z轴、mShownAlpha窗口透明度;mDsDx、mDtDx、mDsDy和mDtDy表示二维变换矩阵;w.mHScale w.mVScale表示窗口的缩放比例

只有计算出的数据和上一次数据不一样才会调用showSurfaceRobustlyLocked输出动画帧。

本文来源:https://www.bwwdw.com/article/hrg6.html

Top