Android Render(一)Activity窗口构成和绘制解析

本文围绕Android Activity窗口展开,介绍了其构成,涉及Activity、PhoneWindow、DecorView等类的作用与创建时机;阐述了窗口创建流程,基于Android 7.1源码分析,展示了各步骤及Surface的创建与数据填充;还说明了窗口组件之间的对应关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阅读者三篇Android绘制文章,会让你对理解Android绘制有帮助:


一、Activity窗口构成

这里我们会介绍到ActivityPhoneWindowDecorViewViewRootImplWindowManagerImplWindowManagerGlobalActivityThreadSurface,关于Activity窗口有很多方面可讲,我这里只侧重于Activity窗口的Render方面来讲解。先来两张张大家早已经烂熟于心的图:

1-1 Activity启动流程图

1-2 Activity构成图

一个Activity的构成有,ActivityPhoneWindowDecorView,再加上DecorView里面的TitleBar和我们填充的content内容,这些还Activity构成需要的具体类,不是一些辅助类,其实还有ViewRootImplWindowManagerImplWindowManagerGlobalActivityThread这几个不可见的辅助类,虽然是Activity构成可见UI界面没用到,但是这几个辅助类都是直接或者间接负责了Activity的构建和绘制的。下面我按照我的理解来一一介绍这些类的作用和被创建时机,有不对的地方还请大家指正:

  • Activity:一个继承ContextThemeWrapper的类,继承自ContextThemeWrapper那么意味着,通过Activity可以访问当前包的资源(getResources、getAssets)和启动其他组件(Activity、Service、Broadcast)以及得到各种服务(getSystemService),并且定义了当前Activity的Theme主题类型 ,关于Context的解释请看:http://www.cnblogs.com/android100/p/Android-Context.html
    并且只有创建了一个Activity才会创建后面的PhoneWindow、DecorView、ViewRootImpl、WindowManagerImpl、和Surface这些类。我这里并没说ActivityThread类,ActivityThread是Android应用的主线程(UI线程),一个应用进程才有一个UI线程。也没有说WindowManagerGlobal类,这个类用了几个数组管理一个应用进程内所有Activity的DecorView和ViewRootImpl以及WindowManager对应关系的。WindowManagerGlobal是一个单例的类,一个应用进程内也只有一个。但是WindowManagerImpl是每一个Activity都有一个的。Activity是在ActivityThread的performLaunchActivity方法中用ClassLoader类加载器创建出来的。

  • PhoneWindow: 一个继承于抽象类Window的类,也是Window的唯一实现类。在Activity中PhoneWindow处在顶级位置,但是PhoneWindow是一个不可见的类,PhoneWindow内的DecorView才是我们可见的UI布局,但是我们可见的UI布局为啥要包装一层PhoneWindow列?经过我的多次查看源代码和推敲,我发现PhoneWindow负责了Activity UI界面顶级布局DecorView的创建,PhoneWindow保存了window attributes即窗口布局属性参数,保存了与WindowManagerService进程通讯的IBinder (取名token)方便去系统WindowManagerService进程通讯,并且负责了用户Key和Touch事件的分发,但是PhoneWindow分发事件也是交给了DecorView来完成的。除了我们Activity在setContent时PhoneWindow创建了DecorView,好像PhoneWindow并没有负责太多的Render的事件。看源码确实就是如此啊!,其实真正的Render操作都在ViewRootImpl类中。PhoneWindow是在Activity的attach方法中new出来的。

  • WindowManagerImpl: 见名知意,就是管理Window的,在这里就是管理PhoneWindow的,每一个Activity都有一个自己的WindowManagerImpl来管理自己的PhoneWindow,WindowManagerImpl其实是用来管理PhoneWindow里面的DecorView的,也可能是DecorView级别的其他的View,还有就是WindowManagerImpl是用来跟一个App全局的PhoneWindow管理器WindowManagerGlobal通信的,添加、移除和更新DecorView层级的View时WindowManagerImpl会调用WindowManagerGlobal中的方法来进行全局管理。WindowManagerImpl是在Activity的attach方法中new PhoneWindow后调用mWindow.setWindowManager方法创建的,其内部是调用setWindowManager的createLocalWindowManager方法new出来的。

  • DecorView: 是一个ViewGroup,继承自FrameLayout,是我们看到的UI界面的顶级容器,DecorView是PhoneWindow的成员。DecorView除了是Activity界面的顶级容器以外,DecorView还是key和touch事件从上向下真正分发开始的源头。事件分发从Activity—》PhoneWindow—》DecorView—》层层向下分发到我们的界面底层。DecorView其实在很多地方都会创建,PhoneWindow内部的getDecorView方法被调用时,要是内部的成员变量mDecor为空的话,就会调用installDecor()方法去创建一个DecorView,最后new 一个DecorView返回,保证调用PhoneWindow的getDecorView获取 DecorView时永远不会为空。我看代码发现PhoneWindow的DecorView第一次调用发生在ActivityThread内的handleResumeActivity方法中,handleResumeActivity方法中还有一个很关键的步骤,就是调用了WindowManagerImpl的addView(DecorView,WindowManager.LayoutParams )方法,进去创建了一个跟DecorView关联的ViewRootImpl类。

  • ViewRootImpl:是一个实现了ViewParent接口的final类。我前面说到了,ViewRootImpl主要是负责Activity的界面Render绘制的,负责整个窗口界面的ViewTree的绘制更新。ViewRootImpl要负责DecorView的绘制,那么ViewRootImpl就需要持有当前Activity的DecorView的引用,是的,的确如此,前面介绍DecorView的创建的时候我说到了DecorView第一次创建发生在ActivityThread内的handleResumeActivity方法中,handleResumeActivity方法中还有一个很关键的步骤,就是调用了WindowManagerImpl的addView(DecorView,WindowManager.LayoutParams )方法,进去创建了一个跟DecorView关联的ViewRootImpl类。WindowManagerImpl的addView方法其实调用了WindowManagerGlobal的addView方法,在这个方法中创建了ViewRootImpl,并且在这个方法中调用了ViewRootImpl的setView方法,使ViewRootImpl持有DecorView的引用。并且把实现了ViewParent接口的自己设置成了DecorView的Parent。这样ViewRootImpl就可以肆无忌惮地操作DecorView了。其实我在调用普通view的invalidate()刷新时,其实是经过层层Parent寻找,最终调用了最顶层的ParentViewRootImpl的invalidate()来判断和处理每次的UI界面刷新的。

  • Surface:一个实现了Parcelable接口的类,对Parcelable接口不了解的,请看我之前的Binder通信的文章:Android IPC之AIDL看这一篇还不够Surface是原始图像缓冲区(raw buffer)的一个句柄,而原始图像缓冲区是由屏幕图像合成器(screen compositor)管理的。得到了Surface这个句柄就可以得到其中的Canvas、原生缓冲器以及其它方面的内容。所以说Surface是生成Canvas的地方,具体就是调用lockCanvas方法获得Canvas。至于Canvas、Paint 和Bitmap的关系我这里就不讲了,后面会有文章来讲这个。Surface是ViewRootImpl的一个final成员变量,伴随ViewRootImpl的创建默认就new一个出来了,但是此时的Surface是一个空的,里面是没有内容的。Surface的数据填充是要跟WindowManagerService交互的,应用进程端Binder通知WindowManagerService进程端创建一个Surface对象,最后是将WindowManagerService进程端的 Surface对象传递到应用进程端并赋值给应用进程的Surface对象,这样窗口可以使用Surface来绘制UI了。因为Surface对象要夸进程传递,所以Surface要实现Parcelable接口。更详细的介绍关于窗口的Surface创建请看老罗的:Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析

二、Activity窗口创建流程

上面的名词介绍其实就是按照窗口的创建流程的顺序来讲的,但是单单是文字不够直观,下面以箭头加方法名的形式展现一下,源码分析流程基于Android7.1



/**1*/ ApplicationThread的onTransact方法接收到SystemServer进程的SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION启动Activity的Binder信息
                ↓
/**2*/ ApplicationThread.scheduleLaunchActivity() //
                ↓
/**3*/ ActivityThread.scheduleLaunchActivity() //安排启动Activity
                ↓
/**4*/ ActivityThread.handleLaunchActivity()  //处理启动Activity
                ↓
/**5*/ ActivityThread.handleResumeActivity() // Activity 的Resume会使DecorView跟ViewRootImpl关联
                ↓
/**6*/ WindowManagerGlobal.addView() //全局保存窗口的信息
                ↓
/**7*/ ViewRootImpl.setView()  //使DecorView和ViewRootImpl关联并绘制界面
                ↓
/**8*/ ViewRootImpl.requestLayout() //请求绘制ViewTree
                ↓
/**9*/ ViewRootImpl.scheduleTraversals() // 安排遍历 
                ↓
/**10*/ ViewRootImpl.doTraversal() //
                ↓
/**11*/ ViewRootImpl.performTraversals() //执行遍历 会根据情况调用relayoutWindow performMeasure performLayout performDraw 等方法 这四个方法跟绘制是紧密相关的
                ↓
/**12*/ ViewRootImpl.relayoutWindow() //窗口第一次创建或者是窗口大小有变化并且窗口可见就会调用此方法 
                ↓
/**13*/ ViewRootImpl.mWindowSession.relayout() //binder通信通知WindowManagerService创建一个跟应用端关联的Surface
                ↓
/**14*/ ViewRootImpl调用performMeasure performLayout performDraw方法绘制UI


其实第五步ActivityThread.handleResumeActivity()方法内会调用到WindowManagerGlobal.addView()方法把窗口绘制完成,紧接着就调用到了activity.makeVisible()方法,其实就是显示出DecorView,因为DecorView创建绘制前是被设置成了INVISIBLE的,Activity中的makeVisible方法就是把绘制完成的DecorView显示出来了:

    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE); //把DecorView设置成可见的
    }

至此我们就看到Activity界面上的UI了。

关于Activity的绘图表面(Surface)的创建过程我还想多说一下,以及Surface跟Activity的对应关系。

Surface是ViewRootImpl的一个final成员变量,伴随ViewRootImpl的创建默认就new一个出来了,但是此时的Surface是一个空的,里面是没有内容的。Surface的数据填充是要跟WindowManagerService交互的,应用进程端Binder通知WindowManagerService进程端创建一个Surface对象,最后是将WindowManagerService进程端的 Surface对象传递到应用进程端并赋值给应用进程的Surface对象,这样窗口可以使用Surface来绘制UI了。因为Surface对象要夸进程传递,所以Surface要实现Parcelable接口。

从Activity窗口创建的流程我们可以知道:

  • 每一个应用程序窗口都对应有两个Java层的Surface对象,其中一个是在WindowManagerService服务这一侧创建的,而另外一个是在应用程序进程这一侧创建的。

  • 在WindowManagerService服务这一侧创建的Java层的Surface对象在C++层关联有一个SurfaceControl对象,用来设置应用窗口的属性,例如,大小和位置等。

  • 在应用程序进程这一侧创建的ava层的Surface对象在C++层关联有一个Surface对象,用来绘制应用程序窗品的UI。

三、Activity窗口组件之间的对应关系

一个设备有一个WindowManagerService进程 有一个SystemServer进程

一个App有一个WindowManagerGlobal类 有一个ActivityThread类 有一个ApplicationThread类

一个App可以有很多个Activity

一个 Activity有一个PhoneWindow类

一个PhoneWindow类有一个ViewRootImpl类

一个PhoneWindow类有一个WindowManagerImpl类

一个ViewRootImpl类有一个Surface类 有一个DecorView类

用一张图表示:

 

Android设备构成图

参考文章:
Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析
从源码看invalidate和requestLayout的区别
Android Render系列规划篇
Android应用层View绘制流程与源码分析


 

<think>好的,用户让我展开WMS动画系统部分的详细流程图。首先,我需要回顾之前的对话,确保这次的内容更详细且符合Android 14的特性。用户之前已经得到了序列图流程图,现在需要更深入的部分。 首先,确定用户的需求是什么。他们可能在进行Android动画开发,或者学习窗口管理系统的工作原理。展开WMS动画系统的细节,可能涉及到它们之间的交互步骤、关键类方法,以及Android 14的新特性。 接下来,我需要检查之前的回答是否有遗漏的关键点。例如,在之前的流程图中提到了PredictiveAnimation、SurfaceTransaction改进WindowMerge。现在需要将这些整合到更详细的流程中,并可能添加更多的参与者,如Choreographer、SurfaceFlinger、RenderThread等。 用户可能需要了解WMS如何处理动画请求,从接收请求到创建动画,再到逐帧更新的过程。同时,动画系统的内部机制,如插值器、估值器、硬件加速等,也是需要展开的部分。还要考虑Android 14的新API,比如setFrameTimeline,以及如何确保动画同步。 需要注意PlantUML的语法是否正确,确保参与者之间的消息传递清晰,并且流程符合逻辑。可能需要分步骤来展示WMS的处理流程动画系统的处理流程,然后展示它们的协作过程。 此外,用户可能希望看到关键类的使用,如WindowState、AnimationSpec、SurfaceControl.Transaction等,这些在代码注释中提及会有帮助。同时,调试优化建议也是用户可能需要的,比如使用systrace或adb命令来验证动画状态。 最后,确保回答结构清晰,分步骤说明,并附上PlantUML代码,方便用户直接使用或修改。检查是否有技术细节需要进步解释,例如预测性动画的处理分支或VSync信号的作用,确保用户能够理解整个流程。</think>根据Android 14架构设计,以下是扩展后的详细流程图(包含WMS与动画系统核心交互): # 、WMS处理动画的详细流程 ```plantuml @startuml title WMS处理窗口动画流程(Android 14) start partition "窗口状态变更阶段" { :应用通过ViewRootImpl\n调用relayoutWindow(); -> WindowManagerService; :WMS#prepareWindowTransaction()\n验证窗口权限; :检查WindowState的\nmAttrsmViewVisibility; if (窗口尺寸/位置变化?) then () :创建PendingLayoutParams; :标记FLAG_LAYOUT_REQUIRED; else () endif } partition "动画决策阶段" { :WMS#applyAnimationLocked()\n(关键决策方法); if (窗口类型是Activity?) then () :获取ActivityRecord中的\nEnter/Exit动画配置; else () :使用WindowManagerPolicy\n提供的默认动画; endif :创建AnimationSpec对象\n(含duration/easing/interpolator); :通过IWindowAnimationRunner\n绑定动画生命周期; } partition "Surface控制阶段" { :调用SurfaceControl.Transaction\n创建事务对象; :设置deferTransactionUntil()\n同步到硬件VSync; if (Android 14新特性) then (启用) :调用setFrameTimeline()\n确保帧时间轴致性; :使用WindowMerge功能\n处理关联窗口同步; endif :通过SurfaceControl.Builder\n配置图层属性; :提交到SurfaceFlinger队列; } partition "动画执行监控" { :注册AnimationProgressListener; loop 每帧回调 :通过Choreographer\n接收VSync信号; :计算currentPlayTime; :调用applyTransformation()\n更新变换矩阵; :触发invalidateRoot()重绘; end :发送ANIMATION_END广播; } stop @enduml ``` # 二、动画系统核心处理流程 ```plantuml @startuml title 动画系统内部处理流程 start :接收WMS的\nstartAnimation()调用; fork :解析AnimationSpec参数\n(duration=300ms, interpolator=Decelerate); fork again :创建ValueAnimator实例\n配置插值器/估值器; end fork :初始化RenderNode动画属性\n(平移/旋转/缩放/透明度); :绑定到RenderThread的\nFrameDrawingCallback; group 硬件加速路径(Android 14优化) :通过HardwareBuffer\n申请图形内存; :调用nativeStartHardwareAnimation(); :使用HWUI线程计算变换矩阵; end group group 软件回退路径 :创建CanvasAnimationRunner; :使用DisplayListCanvas\n进行软件渲染; end group :启动AnimationHandler\n注册VSync监听; repeat :在doFrame()回调中\n计算当前进度; :调用PropertyUpdater\n更新图层属性; :通过SurfaceFlinger\n合成新帧; backward: 收到取消信号?; repeat while (动画未完成且未取消) is () ->是; :执行endDelayedAnimation()\n释放资源; :触发WMS的\nonAnimationFinished()回调; stop @enduml ``` # 三、WMS与动画系统协作流程 ```plantuml @startuml title WMS与动画系统协作时序 participant "ViewRootImpl" as VRI participant "WMS" as WMS participant "AnimationSystem" as AS participant "SurfaceControl" as SC participant "Choreographer" as CHOR participant "RenderThread" as RT VRI -> WMS: relayoutWindow()\n请求布局变更 WMS -> AS: canAnimateWindow()\n检查动画可行性 AS --> WMS: 返回可用动画类型 WMS -> AS: createWindowAnimation()\n创建动画对象 AS -> AS: 加载anim/res/下的\n窗口动画XML资源 WMS -> SC: new Transaction()\n创建Surface事务 SC -> RT: deferTransaction()\n延迟到渲染线程 RT -> CHOR: postFrameCallback()\n注册VSync监听 CHOR -> AS: doFrame()\n垂直同步信号 AS -> AS: calculateCurrentFraction()\n计算动画进度 AS -> SC: setMatrix()\n设置变换矩阵 AS -> SC: setAlpha()\n更新透明度 SC -> RT: applyTransaction()\n提交渲染 RT -> CHOR: 请求下帧回调 loop 持续直到动画结束 CHOR -> AS: doFrame() AS -> SC: 更新属性 end AS -> WMS: notifyAnimationFinished()\n动画完成 WMS -> VRI: reportFinishLayout()\n完成布局 @enduml ``` # 四、关键Android 14新增逻辑标注 ```plantuml note right of WMS Android 14新增: 1. 窗口动画优先级管理(WindowAnimationPriority) 2. 预测性动画预热(preparePredictiveAnimation) 3. 使用WindowOrganizer处理多窗口场景 end note note left of AS Android 14动画系统改进: - 硬件动画路径支持分帧提交 - 新增WindowAnimationTracer调试模块 - 动画资源预加载机制 end note ``` # 五、调试建议 在代码中可插入追踪点: ```plantuml :设置调试标记; note left adb shell setprop debug.wm.animation 1 adb shell dumpsys window animators end note ``` 该设计体现了Android 14在窗口动画方面的核心改进: 1. **事务合并**:通过`mergeTransaction()`减少IPC调用 2. **帧预测**:`FrameTimeline`预估下帧时间 3. **资源隔离**:动画资源使用独立`AnimationThread`处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值