setContentView学习(一)

news/2025/1/11 6:57:22/

setContentView流程分两种情况,一种是继承自Activity的情况,另一种是继承自AppCompatActivity的情况,下面分别介绍。

先说继承自Activity的情况,源码为android-30

public class Activity extends ContextThemeWrapper {public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();}

其中getWindow()返回的是在Activity中定义的Window对象,而Window是一个抽象类,setContentView又是抽象方法,所以必须找到Window的实现类

/*** The only existing implementation of this abstract class is* android.view.PhoneWindow, which you should instantiate when needing a* Window.*/
public abstract class Window {

通过Window类的介绍可以看到,Window只有一个实现类:PhoneWindow,另外通过模拟机调试android-30的源码也可以定位到Window的实现类是 PhoneWindow,看下具体实现

public class PhoneWindow extends Window implements MenuBuilder.Callback {@Overridepublic void setContentView(int layoutResID) {if (mContentParent == null) {installDecor();} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {mContentParent.removeAllViews();}if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {...} else {mLayoutInflater.inflate(layoutResID, mContentParent);}...mContentParentExplicitlySet = true;}

可以看到我们平时写在Activity中的布局被加载到了mContentParent中,那么mContentParent又是哪里创建的,接下来会提到,核心流程主要是看 installDecor()

private void installDecor() {mForceDecorInstall = false;if (mDecor == null) {mDecor = generateDecor(-1);mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);......} else {mDecor.setWindow(this);}if (mContentParent == null) {mContentParent = generateLayout(mDecor);......}
}

通过上面的代码可以看到,setContentView的主要核心流程

1. 创建生成顶层View DecorView

2. 以DecorView为父容器,解析并生成xml布局

其中 generateDecor()的流程比较简单,直接new了一个DecorView并返回,下面看geraterLayout()方法的流程,可以看到generateLayout()方法生成的布局就是mContentParent

注意其传参为上面创建的DecorView

protected ViewGroup generateLayout(DecorView decor) {TypedArray a = getWindowStyle();......int layoutResource;int features = getLocalFeatures();// System.out.println("Features: 0x" + Integer.toHexString(features));if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {......} else if {......} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {layoutResource = R.layout.screen_simple_overlay_action_mode;} else {// Embedded, so no decoration is needed.layoutResource = R.layout.screen_simple;}......mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);......return contentParent;}

这里会根据不同的feature选择不同的系统xml布局,并且最终会返回id为:ID_ANDROID_CONTENT的父布局,ID_ANDROID_CONTENT的值为:

com.android.internal.R.id.content

我们就以最简单的情况为例,也就是最后一种情况,来看下系统布局 screen_simple.xml

<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" /><FrameLayoutandroid: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>

会通过DecorView的 onResourcesLoaded()方法加载上面的布局,注意:其中FrameLayout的id

void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {......mDecorCaptionView = createDecorCaptionView(inflater);final View root = inflater.inflate(layoutResource, null);if (mDecorCaptionView != null) {......} else {// Put it below the color views.addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));}mContentRoot = (ViewGroup) root;initializeElevation();}

同样是使用LayoutInflater解析加载布局,最后通过addView()将解析后的布局添加到DecorView

下面通过一个流程图来对以上流程做一个总结

​​​​​​​

附图:继承自Activity的布局层级图


​​​​​​​

接下来看下继承自AppCompatActivity的流程

    @Overridepublic void setContentView(@LayoutRes int layoutResID) {getDelegate().setContentView(layoutResID);}/*** @return The {@link AppCompatDelegate} being used by this Activity.*/@NonNullpublic AppCompatDelegate getDelegate() {if (mDelegate == null) {mDelegate = AppCompatDelegate.create(this, this);}return mDelegate;}
class AppCompatDelegateImpl extends AppCompatDelegateimplements MenuBuilder.Callback, LayoutInflater.Factory2 {@Overridepublic void setContentView(int resId) {ensureSubDecor();ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);contentParent.removeAllViews();LayoutInflater.from(mContext).inflate(resId, contentParent);mAppCompatWindowCallback.getWrapped().onContentChanged();}private void ensureSubDecor() {if (!mSubDecorInstalled) {mSubDecor = createSubDecor();......}}
}

重点看createSubDecor(),看名字也能猜出来,这里应该是创建DecorView

private ViewGroup createSubDecor() {......ensureWindow();mWindow.getDecorView();......final LayoutInflater inflater = LayoutInflater.from(mContext);ViewGroup subDecor = null;if (!mWindowNoTitle) {if (mIsFloating) {......} else if (mHasActionBar) {......subDecor = (ViewGroup) LayoutInflater.from(themedContext).inflate(R.layout.abc_screen_toolbar, null);mDecorContentParent = (DecorContentParent) subDecor.findViewById(R.id.decor_content_parent);mDecorContentParent.setWindowCallback(getWindowCallback());......}} else {......}......final ContentFrameLayout contentView = 
(ContentFrameLayout) subDecor.findViewById(R.id.action_bar_activity_content);final ViewGroup windowContentView = 
(ViewGroup) mWindow.findViewById(android.R.id.content);if (windowContentView != null) {......windowContentView.setId(View.NO_ID);contentView.setId(android.R.id.content);......}mWindow.setContentView(subDecor);......return subDecor;}

说几个需要注意的点:

1.  mWindow.getDecorView();

2. windowContentView.setId(View.NO_ID);

    contentView.setId(android.R.id.content);

3.  mWindow.setContentView(subDecor);

先说mWindow.getDecorView(),这里的mWindow依然是 PhoneWindow,其中getDecorView()方法里会调用 installDecor()方法,这个方法前面已经说的比较详细了。

接下来看下面这句,这里加载了一个系统布局文件:R.layout.abc_screen_toolbar

subDecor = (ViewGroup) LayoutInflater.from(themedContext).inflate(R.layout.abc_screen_toolbar, null);

来看下这个布局:adc_screen_toolbar.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.ActionBarOverlayLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/decor_content_parent"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"><include layout="@layout/abc_screen_content_include"/><androidx.appcompat.widget.ActionBarContainerandroid:id="@+id/action_bar_container"android:layout_width="match_parentå"android:layout_height="wrap_content"android:layout_alignParentTop="true"style="?attr/actionBarStyle"android:touchscreenBlocksFocus="true"android:keyboardNavigationCluster="true"android:gravity="top"><androidx.appcompat.widget.Toolbarandroid:id="@+id/action_bar"android:layout_width="match_parent"android:layout_height="wrap_content"app:navigationContentDescription="@string/abc_action_bar_up_description"style="?attr/toolbarStyle"/><androidx.appcompat.widget.ActionBarContextViewandroid:id="@+id/action_context_bar"android:layout_width="match_parent"android:layout_height="wrap_content"android:visibility="gone"android:theme="?attr/actionBarTheme"style="?attr/actionModeStyle"/></androidx.appcompat.widget.ActionBarContainer></androidx.appcompat.widget.ActionBarOverlayLayout>

adb_screen_content_include.xml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"><androidx.appcompat.widget.ContentFrameLayoutandroid:id="@id/action_bar_activity_content"android:layout_width="match_parent"android:layout_height="match_parent"android:foregroundGravity="fill_horizontal|top"android:foreground="?android:attr/windowContentOverlay" />
</merge>
final ContentFrameLayout contentView =
(ContentFrameLayout) subDecor.findViewById(R.id.action_bar_activity_content);final ViewGroup windowContentView = 
(ViewGroup) mWindow.findViewById(android.R.id.content);if (windowContentView != null) {windowContentView.setId(View.NO_ID);contentView.setId(android.R.id.content);}

 其中 windowContentView就是继承自Activity时,id为content的FrameLayout,contentView就是上面布局文件里的ContentFrameLayout,注意看下面的两行:

1. windowContentView.setId(View.NO_ID);-->把原来id为content的FrameLayout的id置为空

2. contentView.setId(android.R.id.content);-->把ContentFrameLayout的id设置为content

这样一来adb_screen_content_include.xml里的ContentFrameLayout就相当于继承自Activity时的id为content的FrameLayout,他们的作用是一样的了。

最后看下 mWindow.setContentView(subDecor);这里就是直接调用PhoneWindow的setContentView()方法,流程和上面继承自Activity时的流程又一样了。


http://www.ppmy.cn/news/6956.html

相关文章

【Arduino串口数据保存到excel中常用三种方法】

【Arduino串口数据保存到excel中常用三种方法】 1. 前言2. 利用excel自带Data Streamer读取2.1 启用 Data Streamer 加载项2.2 刷写代码并将微控制器连接到你的电脑2.3 excel画图记录3. 采用插件ArduSpreadsheet读取3.1 安装ArduSpreadsheet3.2 Arduino 代码4. python代码解析4…

【2027. 转换字符串的最少操作次数】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个字符串 s &#xff0c;由 n 个字符组成&#xff0c;每个字符不是 X 就是 O 。 一次 操作 定义为从 s 中选出 三个连续字符 并将选中的每个字符都转换为 O 。注意&#xff0c;如果字符已经是…

智能车|直流电机、编码器与驱动器

智能车|直流电机、编码器与驱动器直流电机直流电机原理减速器编码器编码器简介编码器的工作原理四倍频采集编码器采集程序实现驱动器TB6612FNG 电机驱动器TB6612FNG 的主要参数引脚说明电机整体接线直流电机 直流电机&#xff08;direct current machine&#xff09;是指能将直…

基于Java( jsp+servlet+javabean)+SQL sever 2017实现(Web)高校选课管理系统【100010058】

一、需求分析 开发意义&#xff1a; 随着信息技术不断向深入发展&#xff0c;越来越多的学校开始着手信息化建设。其中学生选课、成绩信息化管理就是其中重要的一块内容。学生选课与成绩信息规模大、项目条数多、信息量庞大&#xff0c;传统的人工管理方式显然已经无法满足要求…

水文监测系统-水文监测站构成 设备 功能 特点介绍以及案例分享

平升电子水文监测系统实现对江河流域水位、降水量、流量、流速、水质、闸门开启度、墒情等数据的实时采集、报送和处理。为防汛抗旱减灾提供科学依据和有效信息共享&#xff0c;保障人民群众生命财产安全&#xff0c;满足水利和经济社会发展对水文服务的需求。 2022年1月&#…

ATAC-seq分析:教程简介(1)

简介 本课程[1]介绍 Bioconductor 中的 ATACseq 分析。 该课程由 2 个部分组成。这将引导您完成正常 ATACseq 分析工作流程的每个步骤。它涵盖比对、QC、peak calling、基因组富集测试、基序富集和差异可及性测试。 环境准备 IGV IGV 可以从 BROAD 网站安装。 》 https://www.b…

C++/Java调用C++动态链接库————附带示例和详细讲解

文章目录0 准备1 C调用动态链接库2 Java调用C动态链接库3 运行0 准备 在CMake中&#xff0c;使用如下的方法把代码编译成动态/静态链接库&#xff1a; # 设置项目名 project(getMatInfo)# 设置c版本 set(CMAKE_CXX_STANDARD 11)# 如果不填写SHARE&#xff0c;默认为静态链接…

Learning to Segment Every Thing

摘要 现有的目标实例分割方法要求所有训练样本都具有分割mask标注。然而&#xff0c;标注新的类别是非常费劲的&#xff0c;因此这将实例分割模型的应用范围限制在100个左右的有标注的类。本文的目的是提出一种新的部分监督的训练模型&#xff0c;以及一种新的权重传递函数&am…