view是如何添加到屏幕上的?
从setContentView出发->
1 | public void setContentView(@LayoutRes int layoutResID) { |
可以看到调用的是getWindow的setContentView方法,
那么getWindow是啥呢?
1 | public Window getWindow() { |
接着看Window
1 | <p>The only existing implementation of this abstract class is |
注意上面的注释,该类唯一的实现是phoneWindow,到这里我们就知道了这个的getWindow实质返回的是一个PhoneWindow的实例。
接着看PhoneWindow的setContentView方法
1 |
|
只需要关注上面的几行代码,如果mContentParent是空,那么调用installDecor方法(如下)。这里的mContentParent是什么呢?看定义的地方它是一个ViewGroup,它里面具体是啥呢?我们继续往下跟。
1 | private void installDecor() { |
这里又出现了mDecor,它又是个啥呢。跟踪generateDecor
1 | protected DecorView generateDecor(int featureId) { |
可以看到mDecor是一个DecorView对象
1 | public class DecorView extends FrameLayout |
它其实就是一个FrameLayout,那么它里面具体是啥呢?我们往下跟
回到installDecor方法,我们再跟下generateLayout方法是如何创建mContentParent的?
1 | protected ViewGroup generateLayout(DecorView decor) { |
这里有一个layoutResource,这个实质就是一个系统的layout xml文件。会根据我们主题不同给它赋不同的值。
接着我们看onResourcesLoaded方法
1 | void onResourcesLoaded(LayoutInflater inflater, int layoutResource) { |
重点关注这两行代码,还记得我们之前分析过mDecor实质是一个frameLayout,这里会把系统的布局文件添加到DecorView里面。到这里我们就知道了DecorView里面具体是啥了。
我们再回到generateLayout方法,会调用PhoneWindow的findViewById方法找一个id,赋值给contentParent返回。这里的findViewById方法实际是getDecorView().findViewById。实质是在mDecor中根据id找它的一个子view。到这里我们就知道了mContentParent具体是个啥了。
我们回到PhoneWindow的setContentView方法
1 |
|
最终会把我们传进来的布局文件填充到mContentParent中。至此,view添加结束。
总结:
PhoneWindow —> DecorView(根据主题不同对应系统的不同布局文件) — >mContentParent(系统布局文件中中的一个子view)—> 我们自己写的布局文件会被加载到mContentParent中。