UI绘制流程(2) - 布局加载及初始化
在我们熟悉的oncreate()方法之中,我们往往会用setContentView()方法来设置我们的布局,那当中又是怎样实现的呢?我们通过源码一探究竟;
setContentView()点进去会走到Window这个抽象类当中。
通过对类的描述可知window实现类为PhoneWindow,在这个类中找到setContentView()方法
此时在这个类中主要做两个事情:一个是installDecor,另一个是inflate。前者是初始化DecorView(根布局),后者是将我们的布局加载到DecorView当中。那么具体过程是怎样实现的的呢?
首先我们来看一下installDecor()方法,
mDecor为decorview对象,decorview继承FrameLayout,由此可知它也是一个ViewGroup。那么decorview承担着怎样的角色呢?其实,decorview是整个ViewTree的最顶层View,主要负责装载各种View和Activity布局。mDecor通过generateDecor()方法实例化。进入到generateDecor()方法之中。
回到installDecor()方法中,接下来往下看
mContentParent:
// mDecor itself, or a child of mDecor where the contents go.(它要么是mDecor本身,要么是mDecor的子类的内容。)
进入到generateLayout(mDecor)方法中;
generateLayout方法当中,发现了在此处进行了大量的requestFeature的调用,也就是说,我们的requestFeature设置其实是在setContentView方法当中就开始了, 这也是为什么我们自己要去getWindow.requestFeature时必须在setContent之前的原因。在generateLayout方法当中接着往下看
由以上代码可以看出,该方法还是做了相当多的工作的,首先根据设置的主题样式来设置DecorView的风格,比如说有没有titlebar之类的,接着为DecorView添加子View,而这里的子View则是上面提到的mContentParent,如果上面设置了FEATURE_NO_ACTIONBAR,那么DecorView就只有mContentParent一个子View,这也解释了上面的疑问:mContentParent是DecorView本身或者是DecorView的一个子元素。我们可以通过前面提到的getWindow.requestFeature进行设置,这里就不在具体说明。默认情况下加载的是screen_simple.xml布局。我们看看布局中有什么?
通过下面这幅图就可以看出DecorView结构关系:
然后我们再回到setContentView()方法中来看inflate方法就比较容易了,就是我们的布局通过mContentParent加载到decorview容器中。
通过这幅图便可以更直观的理解资源加载流程。
小结:DecorView是顶级View,内部有titlebar和contentParent两个子元素,contentParent的id是content,而我们设置的main.xml布局则是contentParent里面的一个子元素。在DecorView创建完毕后,通过setContentView方法中inflate(layoutResID, mContentParent);这里加载了我们设置的main.xml布局文件,并且设置mContentParent为main.xml的父布局。