一、初始化布局
窗体是视图的容器,手机平台窗体是 PhoneWindow 类。
在 package com.android.internal.policy 包中,定义 /** @hide */ DecorView 类,树结构的根视图类型,继承 FrameLayout 类。
在 Activity 类的 attach() 方法,初始化内部 mWindow,即创建 PhoneWindow 对象。
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
创建布局解析器 LayoutInflater 类。
在 Activity 类的 onCreate() 方法,通常 setContentView() 方法 设置布局文件,资源 id 是 R.layout.xxx。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
调用 Window 的 setContentView() 方法。
private DecorView mDecor;//根View
private ViewGroup mContentParent;//存放解析出外部的View
private ViewGroup mContentRoot;//mDecor的直接子View
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//初始化mDecor,创建mContentRoot和mContentParent
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...
} else {
//解析资源ID的View加入到mContentParent的子View中去
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
Window 内部 包含 DecorView。
installDecor() 方法,初始化 DecorView,创建 mContentRoot 和 mContentParent
mContentRoot 是 inflate() xml 文件的视图,添加到顶层视图。
//PhoneWindow的generateLayout方法。mContentRoot创建的代码段。
View in = mLayoutInflater.inflate(layoutResource, null);
//加入顶层视图。
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
系统框架根据 Window 不同 Feature ,选择不同的 layoutResource 布局资源解析,将解析 View 添加到 DecorView 子视图。
举例一种最简单 screen_simple.xml 文件。
mContentParent 视图,通过 findViewById() 方法。
解析资源 id 节点 com.android.internal.R.id.content,FrameLayout 类型。
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
二、XML 解析
LayoutInflater 类,解析 xml 类型 layout 布局文件。
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
根据 int 类型的 resource,生成一个 XmlResourceParser 对象。
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
final String name = parser.getName();
if (TAG_MERGE.equals(name)) {
...
} else {
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
} catch (Exception e) {
} finally {
}
return result;
}
}
XmlPullParser 负责解析 xml 文件,根据 Tag 生成 View 对象。
addView() 方法,将生成的视图添加到 root ,即 mContentParent 视图。
三、总结
DecorView 类,树结构顶层视图类。
mContentRoot 视图,根据 Android_SDK 资源布局 xml 文件解析的视图。
mContentParent ,FrameLayout 类型,mContentRoot 的一个子视图,装载 setContentView() 方法 资源 layout id 视图布局,该视图还包含其他子视图,例如 ActionBar,装载到 ViewStub 节点。
setContentView() 方法,负责 layout 初始化,实现树视图结构,未进行视图测量、布局和绘制。
任重而道远