【Android】源码解析 Activity 的构成

本文是基于 Android 14 的源码解析。

当我们写 Activity 时会调用 setContentView() 方法来加载布局。现在来看看 setContentView() 方法是怎么实现的,源码如下所示:

路径:/frameworks/base/core/java/android/app/Activity.java

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

这里调用了 getWindow().setContentView(layoutResID),getWindow() 指的是什么呢?接着往下看,getWindow() 返回 mWindow,源码如下所示:

路径:/frameworks/base/core/java/android/app/Activity.java

public Window getWindow() {
    return mWindow;
}

那这个 mWindow 又是什么呢?我们继续查看代码,最终在 Activity 的 attach() 方法中发现了 mWindow,源码如下所示:

路径:/frameworks/base/core/java/android/app/Activity.java

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
        IBinder shareableActivityToken) {
    ...

    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    
    ...
}

而 getWindow() 又指的是 PhoneWindow。所以来看看 PhoneWindow 的 setContentView() 方法,源码如下所示:

路径:/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {

    ...

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            view.setLayoutParams(params);
            final Scene newScene = new Scene(mContentParent, view);
            transitionTo(newScene);
        } else {
            mContentParent.addView(view, params);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

    ...
}

原来 mWindow 指的就是 PhoneWindow,PhoneWindow 是继承抽象类 Window 的,这样就知道了getWindow() 得到的是一个 PhoneWindow,因为 Activity 中 setContentView() 方法调用的是 getWindow().setContentView(layoutResID)。

挑关键的接着看,看看上面代码 installDecor() 方法里面做了什么,源码如下所示:

路径:/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

private void installDecor() {
    mForceDecorInstall = false;
    if (mDecor == null) {
        mDecor = generateDecor(-1);
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    } else {
        mDecor.setWindow(this);
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);

        ...
    }
}

在前面的代码中没发现什么,紧接着查看上面代码 generateDecor() 方法里做了什么,源码如下所示:

路径:/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

protected DecorView generateDecor(int featureId) {
    ...
    
    return new DecorView(context, featureId, this, getAttributes());
}

这里创建了一个 DecorView,这个 DecorView 就是 Activity 中的根 View。接着查看 DecorView 的源码,发现 DecorView 是 PhoneWindow 类的内部类,并且继承了 FrameLayout。我们再回到 installDecor() 方法中,查看 generateLayout(mDecor) 做了什么,源码如下所示:

路径:/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

protected ViewGroup generateLayout(DecorView decor) {
    ...

    int layoutResource;
    int features = getLocalFeatures();
    if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogTitleIconsDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else {
            layoutResource = R.layout.screen_title_icons;
        }
        removeFeature(FEATURE_ACTION_BAR);
    } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
            && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
        layoutResource = R.layout.screen_progress;
    } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogCustomTitleDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else {
            layoutResource = R.layout.screen_custom_title;
        }
        removeFeature(FEATURE_ACTION_BAR);
    } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogTitleDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
            layoutResource = a.getResourceId(
                    R.styleable.Window_windowActionBarFullscreenDecorLayout,
                    R.layout.screen_action_bar);
        } else {
            layoutResource = R.layout.screen_title;
        }
    } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
        layoutResource = R.layout.screen_simple_overlay_action_mode;
    } else {
        layoutResource = R.layout.screen_simple;
    }

    ...

    return contentParent;
}

PhoneWindow 的 generateLayout() 方法比较长,这里只截取了一小部分关键的代码,其主要内容就是根据不同的情况加载不同的布局给 layoutResource。现在查看上面代码 R.layout.screen_title,源码如下所示:

路径:/frameworks/base/core/res/res/layout/screen_title.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">
    <!-- Popout bar for action modes -->
    <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:layout_width="match_parent" 
        android:layout_height="?android:attr/windowTitleSize"
        style="?android:attr/windowTitleBackgroundStyle">
        <TextView android:id="@android:id/title" 
            style="?android:attr/windowTitleStyle"
            android:background="@null"
            android:fadingEdge="horizontal"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

上面的 ViewStub 是用来显示 Actionbar 的。下面的两个 FrameLayout:一个是 title,用来显示标题;另一个是 content,用来显示内容。看到上面的源码,大家就知道了一个 Activity 包含一个 Window 对象,这个对象是由 PhoneWindow 来实现的。PhoneWindow 将 DecorView 作为整个应用窗口的根 View,而这个 DecorView 又将屏幕划分为两个区域:一个是 TitleView,另一个是 ContentView,而我们平常做应用所写的布局正是展示在 ContentView 中的,如图所示:
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/429972.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux中服务端开发

1 创建socket,返回一个文件描述符lfd---socket(); 2 将lfd和IP&#xff0c;PROT进行绑定---bind(); 3 将lfd由主动变成被动监听---listen(); 4 接收一个新的连接&#xff0c;得到一个的文件描述符cfd--accept() --该文件描述符用于与客户端通信 5 while(1) { 接受数据&a…

【扩散模型系列3】DiT开源项目

文章目录 DiT原始项目Fast-DiT readmeSamplingTraining训练之前的准备训练DiTPyTorch 训练结果改进训练效果 Evaluation (FID, Inception Score, etc.) 总结 DiT原始项目 该项目仅针对DiT训练&#xff0c;并未包含VAE 的训练 项目地址 论文主页 Fast-DiT readme 该项目仅针…

性能优化篇(七) UI优化注意事项以及使用Sprite Atlas打包精灵图集

UI优化注意事项 1.尽量避免使用IMGUI(OnGUI)来做游戏时的UI&#xff0c;因为IMGUI的开销比较大。 2.如果一个UGUI的控件不需要进行射线检测&#xff0c;则可以取消勾选Raycast Target 3.尽量避免使用完全透明的图片和UI控件。因为即使完全透明&#xff0c;我们看不见它&#xf…

论文笔记:Code Llama: Open Foundation Models for Code

导语 Code Llama是开源模型Llama 2在代码领域的一个专有模型&#xff0c;作者通过在代码数据集上进行进一步训练得到了了适用于该领域的专有模型&#xff0c;并在测试基准中超过了同等参数规模的其他公开模型。 链接&#xff1a;https://arxiv.org/abs/2308.12950机构&#x…

[cg] Games 202 - NPR 非真实感渲染

NPR特性&#xff08;基于真实感渲染&#xff09; 真实感--》翻译成非真实感的过程 NPR风格 需要转换为渲染中的操作 1.描边 B-->普通边界&#xff08;不是下面几种的&#xff09; C-->折痕 M-->材质边界 S-->需要在物体外面一圈上&#xff0c;并且是多个面共享…

win11部署自己的privateGpt(2024-0304)

什么是privateGpt? privategpt开源项目地址 https://github.com/imartinez/privateGPT/tree/main 官方文档 https://docs.privategpt.dev/overview/welcome/welcome PrivateGPT是一个可投入生产的人工智能项目&#xff0c;利用大型语言模型&#xff08;LLMs&#xff09;的…

流行 NFT 的必备指南

​作者&#xff1a;stellafootprint.network 编译&#xff1a;mingfootprint.network 来源&#xff1a;Footprint Analytics Blog 随着爱好者们对 NFT 的兴趣不断高涨&#xff0c;Footprint Analytics 发布了一系列文章&#xff0c;重点介绍各种热门 NFT 系列。这些文章深入…

GBU808-ASEMI整流桥GBU808参数、封装、尺寸

编辑&#xff1a;ll GBU808-ASEMI整流桥GBU808参数、封装、尺寸 型号&#xff1a;GBU808 品牌&#xff1a;ASEMI 封装&#xff1a;GBU-4 最大重复峰值反向电压&#xff1a;800V 最大正向平均整流电流(Vdss)&#xff1a;8A 功率(Pd)&#xff1a;中小功率 芯片个数&#…

【网站项目】075学生信息管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

xss.haozi.me:0x0B

<svg><script>(1)</script>

WebSocket 详解教程

概述 WebSocket 是什么&#xff1f; WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 为什么需要 WebSocket &#xff1f; 了解计算机网络协议的人&#xff0c;应该都知道&#x…

基于云的虚拟桌面基础架构 (VDI)的优势有哪些?

OpenText™ Exceed TurboX™ &#xff08;ETX&#xff09; 长期以来一直是虚拟化在 Linux 主机上运行的图形要求苛刻的软件的黄金标准。ETX 最新版本&#xff08;12.5&#xff09;增加了许多Microsoft Windows功能&#xff0c;包括Windows服务器&#xff0c;使ETX成为任何Windo…

HCIA-Datacom题库(自己整理分类的)_33_DHCP协议多选【7道题】

1.使用动态主机配置协议DHCP分配IP地址有哪些优点? 可以实现IP地址重复利用 工作量大且不好管理 配置信息发生变化(如DNS),只需要管理员在DHCP服务器上修改,方便统一管理 避免IP地址冲突 2.网络中部署了一台DHCP服务器,但是管理员发现部分主机并没有正确获取到该DHCP服务…

Kafka面经

1.Kafka如何保证消息不丢失 生产者&#xff1a; 1.Producer 默认是异步发送消息&#xff0c;这种情况下要确保消息发送成功&#xff0c;有两个方法 a. 把异步发送改成同步发送&#xff0c;这样 producer 就能实时知道消息发送的结果。 b. 添加异步回调函数来监听消息发送的结…

UNIapp实现局域网内在线升级

首先是UNIapp 生成apk 用Hbuilder 进行打包 可以从网站https://www.yunedit.com/reg?gotocert 使用自有证书&#xff0c;目测比直接使用云证书要快一些。 发布apk 网站 用IIS发布即可 注意事项中记录如下内容 第一、需要在 iis 的MiMe 中添加apk 的格式&#xff0c;否则无法…

STM32(15)USART编程

使用USART实现STM32与电脑之间的通信 中介&#xff1a;USB转TTL模块 闭合总开关&#xff0c;外部时钟才会传输到分频器 c8t6手册里面写了&#xff0c;usart最大支持4.5MHz&#xff0c;所以选10 重映射时记得开启AFIO的时钟

Android logcat系统

一 .logcat命令介绍 android log系统: logcat介绍 : logcat是android中的一个命令行工具&#xff0c;可以用于得到程序的log信息. 二.C/Clogcat访问接口 Android系统中的C/C日志接口是通过宏来使用的。在system/core/include/android/log.h定义了日志的级别&#xff1a; /…

opencart3 添加速卖通商品脚本

非爬虫&#xff0c;只能把速卖通商品信息拿下来解析插入到自己的项目里。 刚接触opencart3没多久&#xff0c;有一些新项目需要添加商品&#xff0c;每次手动从速卖通复制信息又很慢&#xff0c;就自己写了一个脚本。 思路&#xff1a;速卖通商品详情页有一段数据包含了几乎所…

Vue-02

开发者工具 安装插件&#xff0c;用于调试 Vue 应用。 https://chrome.zzzmh.cn/index 搜索 Vue &#xff0c;下载 Vue.js Devtools &#xff0c;此插件可以帮助更新信息&#xff0c;而不通过控制台更新&#xff0c;更方便调试。 注&#xff1a;安装插件后&#xff0c;记得在插…

Hello World!第一个labview程序

软件版本&#xff1a; labview myrio 2021英文版 因为没有找到中文版的&#xff0c;据说是myrio没有中文版本 实验内容&#xff1a; 文本显示&#xff0c;程序界面输入任意文本&#xff0c;然后运行程序 在前面板显示出输入的文本 以下为具体步骤&#xff1a; 第一步&…