Activity组件 | 青训营笔记

457 阅读6分钟

这是我参与「第四届青训营 」笔记创作活动的的第1天.

Activity组件是安卓开发者第一个接触到的组件, 也是理解安卓应用程序的重要内容。

本文主要记录Activity组件相关的理论知识。 小蒟蒻浅显的总结, 难免有错误和表述不清, 请批评指正。

Activity的概念

Activity 类是 Android 应用的关键组件,而 Activity 的启动和组合方式则是该平台应用模型的基本组成部分。在编程范式中,应用是通过 main() 方法启动的,而 Android 系统与此不同,它会调用与其生命周期特定阶段相对应的特定回调方法来启动 Activity 实例中的代码。

在我们熟悉的由编译型语言写出的程序中, 会有一个固定的入口即main函数, 程序总是从main函数进入并执行。 而在android系统的应用场景中, app不总是从固定的的位置开始运行, 如我们在qq未运行的情况下打开qq, 会进入聊天列表界面; 在qq不久前使用过时, 会还原退出qq时的界面; 又比如在抖音中选择qq登录, 会直接打开qq中的授权登录界面。

Activity类的作用就是实现形如上面这些场景的功能。

对Activity的一些理解

一个Acivity其实就是一个app界面, app里的界面切换其实就是由一个Activity换成了另一个Activity; Activity的启动可以是显式的(如按下某个按钮, 在按钮控件的代码中我们调用了一个Activity), 也可以是隐式的(由android系统捕捉动作并调用).

Activity的创建

声明Activity

要使应用能够使用 Activity,必须在清单中声明 Activity 及其特定属性。

具体的操作是找到manifests目录的AndroidManifest.xml文件, 在<application>标签中增加一个<activity>标签, 一个activity标签就代表一个activity类, 标签中必须声明的属性是name, 即类名

以下是android studio自动生成的empty界面app中的清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.trudbot.androidapp">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AndroidApp"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

声明 intent 过滤器

Intent 过滤器是 Android 平台的一项非常强大的功能。借助这项功能,您不但可以根据显式请求启动 Activity,还可以根据隐式请求启动 Activity。** **例如,显式请求可能会告诉系统“在 Gmail 应用中启动‘发送电子邮件’Activity”,而隐式请求可能会告诉系统“在任何能够完成此工作的 Activity 中启动‘发送电子邮件’屏幕”。当系统界面询问用户使用哪个应用来执行任务时,这就是 intent 过滤器在起作用。

上面的xml文件中, activity标签如下

<activity
    android:name=".MainActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

intent过滤器中绑定了一个动作<action android:name="android.intent.action.MAIN" /> 即Main, Main动作其实就是打开app, 所以每次我们打开app时都会由系统调用这个Activity, 也就是我们打开app默认显示的界面.

实现Activity类

一个类只有继承了Activity或其子类才是一个Activity类, 在当前的安卓版本中一般继承AppCompatActivity类

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Activity生命周期

当用户浏览、退出和返回到您的应用时,您应用中的 Activity 实例会在其生命周期的不同状态间转换。Activity 类会提供许多回调,这些回调会让 Activity 知晓某个状态已经更改:系统正在创建、停止或恢复某个 Activity,或者正在销毁该 Activity 所在的进程。

大白话讲就是Activity会根据app的状态的切换执行不同的代码.如刚开启这个Activity时, 或者是从app切回了桌面.

为了在 Activity 生命周期的各个阶段之间导航转换,Activity 类提供六个核心回调:onCreate()onStart()onResume()onPause()onStop() 和 onDestroy()。当 Activity 进入新状态时,系统会调用其中每个回调。

这六个回调函数也就是Activity类中要选择性重写的函数, 其中onCreate函数是必须重写的, 它会在系统首次创建 Activity 时触发。Activity 会在创建后进入“已创建”状态。

回调函数更详尽的介绍参加官方文档

Activity 生命周期的简化图示

任务栈

任务是用户在执行某项工作时与之互动的一系列 Activity 的集合。这些 Activity 按照每个 Activity 打开的顺序排列在一个堆栈中。

如从Activity A进入了Activity B时, B就被添加到了栈顶负责与用户交互; 当我们点击回退键时, B被销毁并弹出栈中, A再次成为栈顶.

在任务栈中且非栈顶的Activity会调用onStop后处于停止状态, 系统会保留其界面的当前状态.

有关任务中的每个新 Activity 如何添加到返回堆栈的图示。当用户按返回按钮时,当前 Activity 会销毁,上一个 Activity 将恢复。 每个新 Activity 如何添加到返回堆栈的图示

如果用户不断按回退键, 栈中元素会依次出栈, 直到栈空; 移除堆栈中的所有 Activity 后,该任务将不复存在。

Activity启动模式

试想这样一个场景: 我们在qq 的"消息"页面中点击了导航栏中的"联系人", 又在"联系人"页面中点击了"消息"重新回到了消息页面, 按上面说的任务栈模式, 栈底到栈顶会有消息->联系人->消息三个Activity实例.

"消息"这个Activity被重复创建了两次实例, 而且其实两次都是没什么区别的.这显然不合理.

为了能够优化类似的问题,Android提供四种启动模式来修改系统这一默认行为。

standard模式

默认的模式, 每次启动Activity都会创建新的实例放到栈顶.

singleTask模式

又叫栈内复用模式, 启动某个Activity时, 若栈中已经存在这个Activity的实例, 就会复用这个实例. 复用时, 会将他上面的Activity全部出栈.

singleTop模式

又叫栈顶复用模式, 应对的是"在A中启动A"这样的场景, 此时A已经处于栈顶, 在singleTop模式下会复用A, 并调用onNewIntent方法去除之前操作的痕迹.

singleInstance 模式

此模式的Activity将不能和其它Activity共享任务栈. 这里假设A的启动模式为singleInstance.

  • 当第一次启动A时, 会单独为A新开一个任务栈, 而原任务栈不变
  • 当A已经实例化过、拥有了自己的任务栈, 再在某处启动A时, 会直接复用A的实例, 类似于singleTop
  • 当在A中启动标准模式的Activity, 会为它也新开一个任务栈

引用参考

一篇文章搞懂 Activity 启动模式 - 掘金 (juejin.cn)

Android技能树 — Activity小结 - 掘金 (juejin.cn)

了解 Activity 生命周期  |  Android 开发者  |  Android Developers (google.cn)

彻底弄懂Activity四大启动模式_猴子搬来的救兵Castiel的博客-CSDN博客