setContentView之后
2019-11-01 本文已影响0人
only_run
开发中定义的xml布局文件 是通过setContentView(R.layout.xx)加载给Activity的,那么setContentView方法调用之后发生了什么?
setContentView调用
//AppCompatActivity
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);//1
}
//AppCompatDelegateImpl
public void setContentView(int resId) {
ensureSubDecor();//2
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);//3
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentParent);//4
mAppCompatWindowCallback.getWrapped().onContentChanged();
}
注释1 就一行代码 getDelegate实际获取的是AppCompatDelegateImpl对象,接着调用AppCompatDelegateImpl的setContentView方法
接着调用 注释2 先创建DecorView,然后根据Activity主题 加载不同layout布局创建subDecor添加到DecorView(后面详细描述)
注释3 获取subDecor的contentParent 作为用户布局的parent 在注释4 加载用户布局 到contentParent
ensureSubDecor调用
//AppCompatDelegateImpl
private void ensureSubDecor() {
if (!mSubDecorInstalled) {
mSubDecor = createSubDecor();
...
}
private ViewGroup createSubDecor() {
TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
if (!a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) {
a.recycle();
throw new IllegalStateException(
"You need to use a Theme.AppCompat theme (or descendant) with this activity.");
}
if (a.getBoolean(R.styleable.AppCompatTheme_windowNoTitle, false)) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
} else if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR);
}
if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBarOverlay, false)) {
requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY);
}
if (a.getBoolean(R.styleable.AppCompatTheme_windowActionModeOverlay, false)) {
requestWindowFeature(FEATURE_ACTION_MODE_OVERLAY);
}
mIsFloating = a.getBoolean(R.styleable.AppCompatTheme_android_windowIsFloating, false);
a.recycle();
// Now let's make sure that the Window has installed its decor by retrieving it
ensureWindow();
mWindow.getDecorView();//1
final LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup subDecor = null;
if (!mWindowNoTitle) {
if (mIsFloating) {
// If we're floating, inflate the dialog title decor
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_dialog_title_material, null);//2
// Floating windows can never have an action bar, reset the flags
mHasActionBar = mOverlayActionBar = false;
} else if (mHasActionBar) {
/**
* This needs some explanation. As we can not use the android:theme attribute
* pre-L, we emulate it by manually creating a LayoutInflater using a
* ContextThemeWrapper pointing to actionBarTheme.
*/
TypedValue outValue = new TypedValue();
mContext.getTheme().resolveAttribute(R.attr.actionBarTheme, outValue, true);
Context themedContext;
if (outValue.resourceId != 0) {
themedContext = new ContextThemeWrapper(mContext, outValue.resourceId);
} else {
themedContext = mContext;
}
// Now inflate the view using the themed context and set it as the content view
subDecor = (ViewGroup) LayoutInflater.from(themedContext)
.inflate(R.layout.abc_screen_toolbar, null);//3
mDecorContentParent = (DecorContentParent) subDecor
.findViewById(R.id.decor_content_parent);
mDecorContentParent.setWindowCallback(getWindowCallback());
...
} else {
if (mOverlayActionMode) {
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_screen_simple_overlay_action_mode, null);//4
} else {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);//5
}
...
}
...
// Now set the Window's content view with the decor
mWindow.setContentView(subDecor);//6
...
return subDecor;
}
注释1 获取DecorView 如果为空创建,getDecorView这个方法实际实现是在WindowManagerImpl 这里不再深究了 需要下载android9.0的源码追踪一下;
注释2 ,3 ,4,5 都是根据theme属性配置 读取对应的布局文件 创建对应的View对象 subDecor ,例如注释3 的执行添加是 mHasActionBar 是否存在ActionBar 是不是很熟悉;
注释6 mWindow把subDecor作为DecorView 的子View 进行add;
整理view层级结构如下
根布局结构图.png