1、Activity的setContentView加载逻辑
--> Activity.setContentView(@LayoutRes int layoutResID)
//getWindow()就是PhoneWindow(在attach()中被创建)。
--> getWindow().setContentView(layoutResID);
//创建 DecorView 拿到 Content--------------------------top-----------------------
--> installDecor();
--> mDecor = generateDecor(-1);
--> return new DecorView(context, featureId, this, getAttributes());
--> mContentParent = generateLayout(mDecor);
//根据用户配置,加载layout,下面以R.layout.screen_simple为例
--> layoutResource = R.layout.screen_simple;
--> <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>
--> mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
--> final View root = inflater.inflate(layoutResource, null);
--> return inflate(resource, root, root != null);
--> XmlResourceParser parser = res.getLayout(resource);
--> return inflate(parser, root, attachToRoot);
//加载merge为根节点的view
--> rInflate(parser, root, inflaterContext, attrs, false);
//加载非merge根节点的view
--> final View temp = createViewFromTag(root, name, inflaterContext, attrs);
--> return createViewFromTag(parent, name, context, attrs, false);
--> View view = tryCreateView(parent, name, context, attrs);
//加载sdk中的view
--> if (-1 == name.indexOf('.')) {
view = onCreateView(context, parent, name, attrs);
--> return onCreateView(parent, name, attrs);
--> return onCreateView(name, attrs);
--> return createView(name, "android.view.", attrs);//拼接完整类名
--> return createView(context, name, prefix, attrs);
//通过反射创建View --- 布局的rootView
--> clazz = Class.forName(prefix != null ? (prefix + name) : name, false
,mContext.getClassLoader()).asSubclass(View.class);
--> final View view = constructor.newInstance(args);
} else {
//加载自定义view
view = createView(context, name, null, attrs);
--> clazz = Class.forName(prefix != null ? (prefix + name) : name, false
,mContext.getClassLoader()).asSubclass(View.class);
--> final View view = constructor.newInstance(args);
}
//加载非merge根节点副节点的子view
--> rInflateChildren(parser, temp, attrs, true);
--> rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
--> addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
//找到ID_ANDROID_CONTENT = com.android.internal.R.id.content的view
--> ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
//返回contentView
--> return contentParent;
//创建 DecorView 拿到 Content-------------------------bottom---------------------
//将R.layout.activity_main 渲染到 mContentParent
--> mLayoutInflater.inflate(layoutResID, mContentParent);
//调用setContentView方法后,会设置一个标志位,这也就是为什么在setContentView()调用requestFeature()会崩溃的原因。
--> mContentParentExplicitlySet = true;
2、AppCompatActivity的setContentView加载逻辑
--> AppCompatActivity.setContentView(@LayoutRes int resId)
//getDelegate()就是AppCompatDelegate,AppCompatDelegate是个接口,找到它的实现类AppCompatDelegateImpl
--> getDelegate().setContentView(resId);
--> ensureSubDecor();
--> mSubDecor = createSubDecor();
--> mWindow.getDecorView();
//走到phoneWindow的getDecorView(),这个里面就和上面activity的逻辑一样了.......
//加载R.layout.screen_simple,
--> installDecor();
//根据用户配置,加载layout,下面以R.layout.abc_screen_simple为例
--> subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
--> <androidx.appcompat.widget.FitWindowsLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/action_bar_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true">
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/abc_action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<include layout="@layout/abc_screen_content_include" />
--> <merge xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.appcompat.widget.ContentFrameLayout
android:id="@id/action_bar_activity_content" //把这个view的id重新设置为android.R.id.content
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</merge>
</androidx.appcompat.widget.FitWindowsLinearLayout>
//找到action_bar_activity_content的view
--> final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
R.id.action_bar_activity_content);
//找到android.R.id.content的view
--> final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
//将R.layout.abc_screen_simple中的android.R.id.content的id设置为:NO_ID = -1
--> windowContentView.setId(View.NO_ID);
//设置之前id为action_bar_activity_content的view 的id 为android.R.id.content
--> contentView.setId(android.R.id.content);
--> mWindow.setContentView(subDecor);
--> setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
//把
--> mContentParent.addView(view, params);
//找到R.id.content的view
--> ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
//R.layout.activity_main View 创建,这个逻辑跟上面activity的逻辑一样了.......
--> LayoutInflater.from(mContext).inflate(resId, contentParent);
示意图:
Activity.jpg AppCompatActivity.jpg
网友评论