




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
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(The current thread must have a looper!); 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 CallbackQueueCALLBACK_LAST + 1; for (int i = 0; i now) Log.w(TAG, Frame time is + (timestampNanos - now) * 0.000001f) + ms in the future! Check that graphics HAL is generating vsync + timestamps using the correct timebase.); timestampNanos = now; if (mHavePendingVsync) Log.w(TAG, Already have a pending vsync event. There should only be + one at a time.); 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 = 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_ANIMATIONcpp 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(callback must not be null); 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; mCallbackQueuescallbackType.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, Scheduling next frame in + (nextFrameTime - now) + ms.); 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 = 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 alse; 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来判断窗口
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025北京化工大学化办公室(中心)招聘1人模拟试卷及1套完整答案详解
- 2025年烟台市公费医学生考试选聘(139人)考前自测高频考点模拟试题及一套答案详解
- 2025年福建省厦门中烟益升华滤嘴棒有限责任公司招聘12人考前自测高频考点模拟试题含答案详解
- 2025黑龙江省建工集团招聘17人模拟试卷带答案详解
- 2025年贵金属化合物相关基础化学品项目建议书
- 2025春季江淮汽车校园招聘正式启动考前自测高频考点模拟试题附答案详解(考试直接用)
- 2025广东韶关市始兴县青年就业见习基地招募见习人员4人模拟试卷及参考答案详解一套
- 小学医疗安全知识培训总结课件
- Gly-7-MAD-MDCPT-TFA-生命科学试剂-MCE
- 安全培训效果评价与总结课件
- 2025-2026学年人教版七年级英语上册starterunit1-3单元测试卷(含答案)
- 辽宁省点石联考2025-2026学年高三上学期9月开学英语试题(含答案)
- 2025年乡镇文旅部门工作人员招聘考试必-备知识点与模拟题集
- 抖音达人签约合同协议书
- 森林消防队森林火灾扑救知识培训考试题库题库(附含答案)
- 湖南美术出版社二年级上册美术教学计划
- 2025年西藏自治区事业单位招聘考试综合类专业能力测试试卷(新闻类)押题卷
- VOCs治理设备培训
- 答案时代:AI顾问式电商崛起
- 算力中心能源管理与优化方案
- 中医护理学试题库及答案
评论
0/150
提交评论