setContentView 流程
继承Activity流程
PhoneWindow.setContentView — 主要目的 创建 DecorView 拿到 Content
–》 installDecor(); // 创建 DecorView 拿到 mContentParent
–》 mDecor = generateDecor(-1);
–》 new DecorView()
–》 mContentParent = generateLayout(mDecor);
a、先获取对应属性的设置
–》 R.layout.screen_simple --》 @android:id/content --》 mContentParent
// R.layout.screen_simple --》 添加到 DecorView(FrameLayout)
–》 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
–》 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
–》 mLayoutInflater.inflate(layoutResID, mContentParent); // R.layout.activity_main 渲染到 mContentParent

面试: Activity的setContentView 调用PhoneWindow 再调用到decorView里会又一个screen_simple.xml,这个xml有viewStub和fragmentLayout组成,我们的布局就会加载到这个fragment上。AppCompatActivity前面流程基本和Activity一致,唯一的区别就是AppCompatActivity会在fragment上再嵌套一层,然后将原来view一个个删掉,然后添加到新的布局上面,然后就会去解析xml布局,LayoutInflater这里进行加载。
创建phnWindow
ActivityThread.performLaunchActivity
–>activity.attach
–> new PhoneWindow()
–>mInstrumentation.callActivityOnCreate
PhoneWindow —》分为3类,哪些地方会创建
1.Activity
2.Dialog
3.PopupWindow
4.Toast
继承 AppCompatActivity 的流程
AppCompatDelegate.setContentView
–> ensureSubDecor();
–> mSubDecor = createSubDecor();
–> ensureWindow(); // 从Activity 那PhoneWindow
–> mWindow.getDecorView();
–> installDecor(); // mContentParent
。。。 。。。 //看Activity的流程
// R.layout.screen_simple 里面的 content —》 把 content 的 View 复制到 R.id.action_bar_activity_content
–> final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
删除掉原来的activity的view,写入到新的contentView里
while (windowContentView.getChildCount() > 0) {
final View child = windowContentView.getChildAt(0);
windowContentView.removeViewAt(0);
contentView.addView(child);
}
--> windowContentView.setId(View.NO_ID); // 将原始R.layout.screen_simple的 content id 置为 NO_ID
--> contentView.setId(android.R.id.content); // subDecerView R.id.action_bar_activity_content --> 置为 content
--> mWindow.setContentView(subDecor); //
–> ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);

xml加载流程
// R.layout.activity_main View 创建
–> LayoutInflater.from(mContext).inflate(resId, contentParent);
// 通过反射创建View — 布局的rootView
–> final View temp = createViewFromTag(root, name, inflaterContext, attrs);
if (-1 == name.indexOf('.')) { //是否是sdk(非源码自带的布局如LinearLayout)
view = onCreateView(context, parent, name, attrs);
--》 PhoneLayoutInflater.onCreateView(name, attrs);
//作用:补全类名:
private static final String[] sClassPrefixList = {
"android.widget.",
"android.webkit.",
"android.app.",
"android.view."
};
--> View view = createView(name, prefix, attrs);//同下方调用一样的方法
} else { // name = androidx.constraintlayout.widget.ConstraintLayout
view = createView(context, name, null, attrs);
// 通过反射创建 View 对象
--> clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
mContext.getClassLoader()).asSubclass(View.class);
--> constructor = clazz.getConstructor(mConstructorSignature);//构造方法
--> final View view = constructor.newInstance(args);
}
--> rInflateChildren(parser, temp, attrs, true); // 创建子View
--> rInflate
--> View view = createViewFromTag(parent, name, context, attrs);
LayoutInflate的参数的作用
// 方式一:将布局添加成功
View view = inflater.inflate(R.layout.inflate_layout, ll, true);
// 方式二:报错,一个View只能有一个父亲(The specified child already has a parent.)
View view = inflater.inflate(R.layout.inflate_layout, ll, true); // 已经addView
ll.addView(view);
// 方式三:布局成功,第三个参数为false
// 目的:想要 inflate_layout 的根节点的属性(宽高)有效,又不想让其处于某一个容器中
View view = inflater.inflate(R.layout.inflate_layout, ll, false);
ll.addView(view);
// 方式四:root = null,这个时候不管第三个参数是什么,显示效果一样
// inflate_layout 的根节点的属性(宽高)设置无效,只是包裹子View,
// 但是子View(Button)有效,因为Button是出于容器下的
View view = inflater.inflate(R.layout.inflate_layout, null, false);
ll.addView(view);
View 没有父容器 —》 尺寸大小 参数的设置无效 View的绘制流程

https://blog.csdn.net/m0_37707561/article/details/125890487
Q:LayoutInflater 的 inflate 方法不同参数对加载的View有什么区别?
A:主要是 ViewGroup root 和 boolean attachToRoot 这两个参数。当 root 为 null 时,布局文件最外层设置的 layout_xxx 属性就会失效。而当 root 不为 null 时, attachToRoot 为 true 就是调用 root.addView() 去添布局,此时 root 得是ViewGroup,否则会报错;而当 attachToRoot 为 false,则会正常设置 最外层 layout_xxx 属性给当前得布局文件。
文章详细解释了Android中`setContentView`在Activity和AppCompatActivity中的执行流程,包括PhoneWindow、DecorView的创建过程,以及LayoutInflater如何解析XML并加载到视图中,特别关注了AppCompatActivity中对原有布局的替换操作。
494

被折叠的 条评论
为什么被折叠?



