使用 setContentView 好长时间了,天真的以为 Activity 的根布局就是我们的布局,今天才算摸清楚。先看结果(所有源码取自 API27):
特别感谢 @细卷子老师 精彩的博客
特别感谢 @明潮老师 博客中的图片,受益匪浅
![](https://img.haomeiwen.com/i5226948/799d71d5549a15c7.png)
说明:其中(1)(2)并不算布局,但探索问题的源头从这两个开始。
(1)Activity
学习 Android 第一节课就是新建一个界面(Activity),学习使用 setContentView(int layoutResource),这是 Activity 的方法,从源码看出,是调用 PhoneWindow 的 setContentView。
![](https://img.haomeiwen.com/i5226948/89ded9a11c5ac607.png)
(2)PhoneWindow
PhoneWindow 是 Window 的子类,实现了 Window 中的很多方法,包括 setContentView。源码中看出,开始创建布局,也就是我们的根布局,DecorView。
![](https://img.haomeiwen.com/i5226948/0ed02726b19398c9.png)
(3)DecorView
DecorView 是 FrameLayout 的子类,是 Activity 的根布局。他有一个 mFeatureId 属性,用来标识是否是根布局(因为 DecorView 也可以作为一个普通 View 来使用),在构造函数中传入。首先看 installDecor 源码,分为两步,第1步,初始化 DecorView,第2步,初始化 DecorView 内部,并找到 mContentParent。
![](https://img.haomeiwen.com/i5226948/bd5971e369f3eb8d.png)
1、初始化 DecorView
![](https://img.haomeiwen.com/i5226948/9170323daabadf9c.png)
(4)某种布局(mContentRoot)
这部分,每个版本有所不同,但 mContentRoot 一定包含或本身就是 mContentParent。
在 installDecor 方法的第2步,generateLayout,初始化 mContentRoot。从源码看出,同样是两步,第1步,初始化 DecorView 内部,大部分是 LinearLayout,其中包含 id 为 content 的 FrameLayout,也就是我们的 mContentParent,第2步就是找到 mContentPratent,然后返回给上一步。
![](https://img.haomeiwen.com/i5226948/d34b0ec7051e1718.png)
1、将 layoutResource 添加到 DecorView 中,这是 DecorView 的方法
![](https://img.haomeiwen.com/i5226948/553dabd3964df9de.png)
(5)FrameLayout(mContentParent)
我们的 content(FrameLayout)已经在 generateLayout 的第2步找到了,并在 installDecor 的第2步赋值给 mContentParent。
(6)设置自己的布局
到目前,整个布局的架子已经搭建好了,最后一步就是将我们自己的布局加入到 content 中。
现在应该从 generateLayout 返回到 installDecor 返回到 PhoneWindow.setContentView。看源码,layoutResID 是我们布局的 id,现在将布局添加到 mContentParent 中。
![](https://img.haomeiwen.com/i5226948/fa5b096df129c10e.png)
![](https://img.haomeiwen.com/i5226948/326e6da0b91f2f0f.png)
网友评论