从setContentView了解Android UI绘制流程
初学android的朋友可能会有这样一种疑问,为什么在setContentView方法里指定对应的layout资源,就能把对应的布局加载到屏幕上。那么,咱们现在就开始从源码来分析这样一个问题。
首先,在onCreate方法里面,调用了setContentView方法,这个方法是来自Activity的。我们进入到Activity的源码:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
这里调用了getWindow的setContentView方法,那getWindow返回了一个Window对象,而Window是一个抽象类,它的唯一子类叫做PhoneWindow,那么这个window是什么时候被赋值的呢?是在attach里面直接new出来的
mWindow = new PhoneWindow(this, window, activityConfigCallback)
我们进入到PhoneWindow看一下setContentView方法。
这个方法主要做了两件事:
1.installDecor
installDecor这个方法干了两件事
1.1 generateDecor
这里实例化了一个DecorView ,DecorView继承自FrameLayout,用来装载我们的页面布局
1.2 generateLayout
如果没有特殊情况的话,是将R.layout.screen_simple这样一个布局加载到DecorView中
布局文件如下:是一个纵向布局 ViewStup用于摆放action bar,而FrameLayout用于摆放我们布局文件中的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
这一步骤完成之后,mContentParent就不为null了,mContentParent实际上是一个ViewGroup,它对应的类型是R.id.content,在R.layout.screen_simple中对应的实际上就是一个FrameLayout。
2.将setContentView传入的layout解析并绘制
主要代码就是 mLayoutInflater.inflate(layoutResID, mContentParent);
我们来看一下这个方法:
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
这个方法最终返回一个View,也就是向mContentParent中添加子View。
主要代码 :
View temp = createViewFromTag(root, name, inflaterContext, attrs);
temp.setLayoutParams(params);
rInflateChildren(parser, temp, attrs, true);
root.addView(temp, params);
其中涉及到的xml解析可见下图
这样,我们整个布局就加载到了对应的Activity当中了,那么,布局是什么时候开始绘制,如何绘制到屏幕上的呢?请看下回分解。
总结:最终Activity的层次结构可以总结为下图: