
1. View添加到屏幕窗口的源码分析
入口:在Activity的onCreate中调用setContentView传入布局资源ID。 接着调用 :getWindow().setContentView(layoutResID); 其中 getWindow,返回就 Window 的唯一实现类 PhoneWindow。
java
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
PhoneWindow:
java
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...
}
...
}
java
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor(-1); // return new DecorView
...
} else {
...
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
}
在 PhoneWindow 的 setContentView 中,会调用 installDecor 里面的方法执行 generateDecor 创建 DecorView。 DecorView继承自FrameLayout,是应用窗口的顶层View容器。 然后将 mDecor 传进 generateLayout, 该方法根据系统主题属性(如是否有ActionBar、浮动窗口等)确定不同的layoutResource(例如R.layout.screen_simple)。 通过 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource); 将得到的布局资源添加到 DecorView 中。 然后通过 findViewById 获取 id 为 com.android.internal.R.id.content 的基础布局,一般为 FrameLayout,后面我们的界面就是绘制在这个布局里面的。 最终返回这个 contentParent 
小结
PhoneWindow持有DecorView。DecorView中包含根据主题生成的基础布局(如screen_simple),该基础布局通常包含标题栏(Title/ActionBar)和内容区域(ID为content的FrameLayout)。我们的XML布局最终被添加到这个content容器中。
2. View绘制流程的触发机制
绘制的入口是ActivityThread的handleResumeActivity方法。 该方法在执行performResumeActivity(回调onResume)后,初始化WindowManager.LayoutParams,并调用WindowManager的addView方法。
WindowManager 来源:
Activity中的WindowManager接口实现类为WindowManagerImpl。WindowManagerImpl的addView方法委托给WindowManagerGlobal的addView方法。WindowManagerGlobal.addView中创建ViewRootImpl对象,并将DecorView、布局参数等与之关联。
关键调用:root.setView(view, wparams, panelParentView),其中root即为ViewRootImpl实例。
3. 绘制核心流程:PerformTraversals
在ViewRootImpl.setView中调用requestLayout()。该方法首先通过checkThread()确保当前操作在主线程执行,随后调用scheduledTraversals()。 scheduledTraversals()通过Choreographer(编舞者) post一个TraversalRunnable。当VSync信号到来时,TraversalRunnable的run方法被执行,进而调用doTraversal()。 doTraversal()的核心是调用performTraversals()。在此方法中,依次执行UI绘制的三个关键步骤:
- 测量 (Measure):调用
performMeasure(),确定View的大小。 - 布局 (Layout):调用
performLayout(),确定View的位置。 - 绘制 (Draw):调用
performDraw(),将View内容渲染到屏幕上。