竟如此简单,一文看懂DecorView的一生

💡 原文中文,约8800字,阅读约需21分钟。
📝

内容提要

DecorView是Android应用程序中的根视图,负责承载应用的视图结构。它与Window、Activity和ViewRootImpl有联系。通过setContentView方法将布局加载到DecorView中。ViewRootImpl负责初始化视图层次结构、处理布局和事件分发。DecorView的创建需要经过Activity的启动和PhoneWindow的初始化。最后,DecorView被添加到WindowManager中,由ViewRootImpl进行后续制作。

🔎

延伸解读

DecorView 与 Window、Activity 的职责划分

DecorView 是视图树的根,但它的创建和显示并非独立完成。Activity 在 attach 时创建 PhoneWindow,Window 作为容器承载 DecorView,而 ViewRootImpl 则负责将 DecorView 连接到窗口系统。理解这三者的分工,有助于在开发中定位问题:例如视图不显示可能涉及 WindowManager 添加时机,而布局错乱则可能与 ViewRootImpl 的测量流程有关。

为什么 onCreate 中拿不到 View 的宽高

文章指出,DecorView 被添加到 WindowManager 是在 onResume 之后,由 ActivityThread 的 handleResumeActivity 触发。在此之前,视图尚未与窗口系统建立连接,因此无法进行测量和布局。这解释了在 onCreate 或 onResume 中直接调用 getWidth() 或 getHeight() 通常返回 0 的原因。若需获取宽高,应使用 View.post 或 OnGlobalLayoutListener 等延迟机制。

ViewRootImpl 在渲染流程中的核心作用

ViewRootImpl 是连接 WindowManager 和 DecorView 的桥梁,负责触发测量、布局、绘制以及事件分发。当 DecorView 通过 WindowManagerGlobal.addView 添加时,会创建 ViewRootImpl 并调用 setView,进而执行 requestLayout。requestLayout 会检查线程并安排遍历,最终在屏幕刷新信号到来时执行 performTraversals。这揭示了 UI 渲染的异步性和线程约束。

从源码看 setContentView 的实质

setContentView 并非直接设置 Activity 的布局,而是通过 getWindow().setContentView() 委托给 PhoneWindow。PhoneWindow 在 installDecor 中创建 DecorView 和内容父容器 mContentParent,再将布局资源解析并添加到 mContentParent 中。因此,开发者设置的布局只是 DecorView 的一部分,DecorView 还可能包含状态栏、导航栏等窗口级元素。这有助于理解视图层次的完整结构。

❓

Q&A

什么是DecorView,它在Android应用中有什么作用?

DecorView是Android应用程序中的根视图,负责承载应用的视图结构,是管理和显示应用界面的核心组件。

DecorView是如何与Activity和Window关联的?

每个Activity都有一个与之关联的Window,Window负责承载DecorView,Activity通过setContentView方法将布局加载到DecorView中。

DecorView的创建流程是怎样的?

DecorView的创建通常在Activity的onCreate方法中开始,通过调用setContentView方法触发,随后被添加到WindowManager中。

ViewRootImpl在DecorView的生命周期中起什么作用?

ViewRootImpl是连接Window和DecorView的桥梁,负责初始化视图层次结构、处理布局和事件分发。

setContentView方法在DecorView的创建中扮演什么角色?

setContentView方法用于加载布局,将其作为子视图添加到DecorView中,并触发DecorView的初始化。

DecorView是如何被添加到WindowManager中的?

在Activity的onResume方法之后,DecorView被添加到WindowManager中,从而显示在屏幕上。

🏷️

标签

➡️

继续阅读