我们先来看一下Android中View视图在Activity中的整个层级关系:
androidView视图.png包含关系:Activity中有个成员变量Window,Window是个抽象类,它的实现类是PhoneWindow,PhoneWindow有一个成员变量DecorView.
Phonewindow对象创建的开始
简要说一下整个调用流程:
入口:ActivityThread#handleLaunchActivity() ->ActivityThread#performLaunchActivity()
开始创建PhoneWindow : performLaunchActivity() -> Activity.attach()
后续的DecorView的创建主要在SetContentView中,后面会分析到.
// Activity类
final void attach(...) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
// 创建PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
}
setContentView登场
学过Android的都知道,setContentView通常会在Acvitity中的Oncreate方法中调用,那么SetContentView到底做了什么呢?
DecorView的创建
DecorView创建来龙去脉 Activity#setConTentView -> PhoneWindow#setConTentView -> PhoneWindow#install -> PhoneWindow#generateDecor
代码调用链如下:
// Activity类
public void setContentView(@LayoutRes int layoutResID) {
// 获取PhoneWindow对象,调用PhoneWindow中的SetContentView方法
getWindow().setContentView(layoutResID);
// 初始化ActionBar
initWindowDecorActionBar();
}
// PhoneWindow类
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
// 创建DecorView对象实例
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
// 核心代码,后面重点讲这里面干了什么
mLayoutInflater.inflate(layoutResID, mContentParent);
}
...
}
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// 真正创建decorView的地方
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
...
}
protected DecorView generateDecor(int featureId) {
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
// 返回创建的DecorView对象,至此DecorView创建完毕
return new DecorView(context, featureId, this, getAttributes());
}
LayoutInflater.inflate(layoutResID, mContentParent)做了什么
参数:
-
第一个参数layoutResId:资源文件id(对应xxx.xml)
-
第二个参数mContentParent: viewGroup对象,表示创建的view位于viewGroup下
逻辑处理过程如下:
// LayoutInflater类
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
// 第三个参数表示创建的view是否依附于viewGroup下
return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
// 解析xml,返回XmlResourceParser对象,通过该对象可以读取xml中的view定义
final XmlResourceParser parser = res.getLayout(resource);
try {
// 通过XmlResourceParser创建出一个view层级(一棵view数)
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
...
...
// 获取xml中所有的属性
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
// Temp is the root view that was found in the xml
// 创建,取得当前xml的根view
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
...
...
...
// Inflate all children under temp against its context.
// 创建根view下的子view
rInflateChildren(parser, temp, attrs, true);
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
return result;
}
}
final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
}
void rInflate(XmlPullParser parser, View parent, Context context,
AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
boolean pendingRequestFocus = false;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) {
pendingRequestFocus = true;
consumeChildElements(parser);
} else if (TAG_TAG.equals(name)) {
parseViewTag(parser, parent, attrs);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, context, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else {
// 此处递归创建子view,最终会得到一棵view树
final View view = createViewFromTag(parent, name, context, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflateChildren(parser, view, attrs, true);
viewGroup.addView(view, params);
}
}
if (pendingRequestFocus) {
parent.restoreDefaultFocus();
}
if (finishInflate) {
parent.onFinishInflate();
}
}
总结一下 LayoutInflater.inflate一共做了什么:
解析xml得到XmlPullParser对象 -> 通过XmlPullParser对象创建出viewRoot -> 把创建处理的view添加到父view中 -> 递归创建子view并把创建处理的view添加到父view中,最后得到一棵viewTree
以上就是SetContentView的所有过程
更多Android分享请关注公众号:Android开发
网友评论