setContentView学习(一)

news/2024/7/5 2:28:15

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 {

    @Override
    public 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布局,我们就以最简单的情况为例,也就是最后一种情况,来看下系统布局 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" />
    <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>

会通过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的布局层级图


​​​​​​​


http://lihuaxi.xjx100.cn/news/479298.html

相关文章

ArcGIS Pro 制作这种地图海报

ArcMap 版本与 ArcGIS Pro 版本的制图功能相差太多,无论从美观上还是制图效率都远远优于 ArcMap,用了一段时间的 ArcGIS Pro ,真心推荐有条件的大家赶紧试一试! 一个软件也能搞定一张不错的海报哦!----吐槽:好的设计真的是门花时间的活,这个教程大概花了我7小时左右,我…

函数的间断点例题

前置知识&#xff1a;函数的间断点 设f(x){e1x−1,x>0ln⁡(1x)−1,−1<x≤0f(x)\left\{\begin{matrix}e^{\frac{1}{x-1}},\qquad \qquad \qquad x>0 \\\ln(1x)-1,\quad -1<x\leq 0\end{matrix}\right.f(x){ex−11​,x>0ln(1x)−1,−1<x≤0​&#xff0c;求f…

竞速新能源赛道,长城汽车需要“爆款”车型做尖刀

出品 | 何玺 排版 | 叶媛 11月&#xff0c;长城汽车发布最新全球品牌战略&#xff0c;并着眼于2023年的工作部署&#xff0c;对整个品牌资源和组织架构进行了深度调整。在全新的组织架构阵列支撑下&#xff0c;长城汽车将集中优势资源&#xff0c;以全球化、高端化为抓手&…

定时循环执行Python脚本 —— 定时执行专家

目录 提前准备 方案一、执行DOS命令 方式 1、在《定时执行专家》里新建“执行DOS命令”任务 方案二、执行脚本文件 方式 1、编写 .bat 脚本&#xff0c;用来执行Python脚本 2、在《定时执行专家》里新建“执行脚本文件”任务 本文提供两种使用《定时执行专家》定时循环执…

DaVinci:曲线之 HSL 曲线

调色页面&#xff1a;曲线Color&#xff1a;CurvesH 指的是色相 Hue&#xff0c;S 指的是饱和度 Saturation&#xff0c;L 指的是亮度 Luminance。DaVinci Resolve 的曲线调板中&#xff0c;除了自定义曲线&#xff0c;还提供了六种基于色相、饱和度或亮度的调节曲线&#xff0…

安全分析工作流定制

安全分析工作流定制 工作流&#xff08;Workflow&#xff09;是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。工 作流系统是以规格化的流程描述作为输入的软件组件&#xff0c;它维护流程的运行状态&#xff0c;并在人和应 用之间分派活动。 为实现特定业务目标&a…

客快物流大数据项目(九十八):ClickHouse的SQL函数

文章目录 ClickHouse的SQL函数 一、​​​​​​​​​​​​​​类型检测函数

创建Configuration及单例模式

创建XPath对象&#xff1a; XPathFactory factory XPathFactory.newInstance();this.xpath factory.newXPath(); 创建Document对象&#xff1a;&#xff08;DOM解析&#xff09; //JDK提供的文档解析工厂对象DocumentBuilderFactory factory DocumentBuilderFactory.newIn…