当前位置: 首页 > news >正文

【Android】Activity 的生命周期和启动模式

文章目录

  • Activity 的生命周期和启动模式
    • 1. 任务和返回栈
    • 2. Activity 的四种状态
      • 2.1 运行状态
      • 2.2 暂停状态
      • 2.3 停止状态
      • 2.4 销毁状态
    • 3. Activity的生命周期
      • 3.1 生命周期回调方法
      • 3.2 演示 Activity 的生命周期
    • 4. Activity的启动模式
      • 4.1 standard(标准模式)
      • 4.2 singleTop(栈顶复用模式)
      • 4.3 singleTask(栈内复用模式)
      • 4.4 singleInstance(单实例模式)
      • 4.5 使用 Intent Flags

Activity 的生命周期和启动模式

1. 任务和返回栈

《第一行代码》原文如下:

Android 是使用任务(Task)来管理活动(Activity)的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。栈是一种后进先出的数据结构,在默认情况下,每当我们启动一个新的活动,他会在返回栈入栈,并处于栈顶的位置。而每当我们按下 Back 键或调用 finish() 方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户。

下图展示了返回栈是如何管理活动入栈出栈操作的:

在这里插入图片描述

返回栈就像一个“页面历史记录”,记录了用户打开的 Activity 的顺序;任务是一个运行中应用组件的集合,包含一个返回栈。

2. Activity 的四种状态

在Android开发中,活动状态(Activity Status)指的是一个活动在其生命周期中的不同状态。主要有以下几种状态:

  • 运行状态(Running):活动在屏幕前景中显示,用户可以与之交互。
  • 暂停状态(Paused):活动仍然可见,但失去焦点,用户无法与之交互。
  • 停止状态(Stopped):活动完全不可见,但仍然保留其状态和成员信息。
  • 销毁状态(Destroyed):活动被系统销毁,释放资源。

这些状态的管理对于提升应用的性能和用户体验至关重要。

2.1 运行状态

当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。系统最不愿回收的就是处于运行状态的活动,因为这会带来非常差的用户体验。

2.2 暂停状态

当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。你可能会觉得既然活动已经不在栈顶了,还怎么会可见呢?这是因为并不是每一个活动都会占满整个屏幕的,比如对话框形式的活动只会占用屏幕中间的部分区域,你很快就会在后面看到这种活动。处于暂停状态的活动仍然是完全存活着的,系统也不愿意去回收这种活动(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种活动。

2.3 停止状态

当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能会被系统回收。

2.4 销毁状态

当一个活动从返回栈中移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足。

3. Activity的生命周期

在 Android 系统中,Activity 是用户界面的基本构建块,代表一个单一的屏幕。用户与应用交互时(如打开新屏幕、返回、切换到其他应用、屏幕旋转等),Activity 会经历一系列状态变化。Android 系统通过回调方法通知 Activity 这些状态变化,开发者需要覆盖这些方法来管理资源、保存数据、提供流畅的用户体验。

回调方法:当 Activity 在状态间转换时,系统会自动调用的方法(如 onCreate(), onStart())。开发者重写这些方法来执行特定操作。

3.1 生命周期回调方法

Activity 类中定义了7 个回调方法:

  1. onCreate()
    • 触发时机: Activity 首次创建时调用。这是生命周期中必须实现的方法。
    • 主要职责:
      • 执行基本应用启动逻辑(只应执行一次)。
      • 调用 setContentView() 来设置 Activity 的布局。
      • 初始化关键的、生命周期感知的组件(如 ViewModel)。
      • 绑定数据到 UI(如果数据已准备好)。
    • 下一个状态: Started (系统紧接着调用 onStart())。
  2. onStart()
  • 触发时机: Activity 变得可见给用户时调用(但可能不在前台,例如被一个非全屏对话框或另一个透明 Activity 部分覆盖)。在 onCreate() 之后或 Activity 从 Stopped 状态恢复时调用。
  • 主要职责:
    • 准备让 Activity 进入前台并与用户交互所需的资源(这些资源在 onStop() 中释放)。
    • 注册需要响应 Activity 可见性的监听器(如广播接收器、位置更新监听器)。
    • 启动 UI 更新所需的动画或线程。
  • 下一个状态: Resumed (如果 Activity 进入前台) 或 Stopped (如果 Activity 被完全隐藏)。
  1. onResume()
    • 触发时机: Activity 位于栈顶获得用户焦点时调用。用户正在与 Activity 交互。
    • 主要职责:
      • 启动或恢复需要用户交互的组件(如摄像头、高精度位置更新、传感器、动画、独占的音频/视频资源)。
      • 确保 UI 是最新的(数据可能在上次暂停后发生了变化)。
    • 下一个状态: Paused (当 Activity 失去焦点但仍部分可见时)。
  2. onPause()
    • 触发时机: Activity 失去焦点但仍部分可见时调用(例如,被一个非全屏对话框、透明 Activity 或系统 UI 如权限对话框部分覆盖)。或者当 Activity 即将进入 Stopped 状态时(系统会在 onStop() 之前调用 onPause())。
    • 主要职责:
      • 释放或调整在 onResume() 中获取的、不需要在暂停状态下运行的独占资源(如摄像头、传感器、高精度定位、独占音频焦点)。
      • 提交未保存的更改(但轻量级的,因为系统可能很快调用 onResume())。不建议执行 CPU 密集型操作或持久化数据(如数据库写入),这会延迟到下一个 Activity 的转换。
      • 为进入 Stopped 状态做准备。
    • 下一个状态: Resumed (如果用户返回到该 Activity) 或 Stopped (如果 Activity 被完全隐藏)。
  3. onStop()
    • 触发时机: Activity 对用户完全不可见时调用(例如,被另一个 Activity 完全覆盖、用户切换到其他应用、或 Activity 本身即将被销毁)。
    • 主要职责:
      • 释放或调整所有在 onStart() 中获取的、不需要在不可见状态下运行的资源(如广播接收器、位置更新监听器、UI 动画线程)。
      • 执行 CPU 相对密集的关闭操作(如将数据保存到数据库)。
      • 保存当前的 UI 状态(通过 onSaveInstanceState())。
    • 下一个状态: Restarted (如果 Activity 重新变得可见) 或 Destroyed (如果系统需要回收内存或用户显式关闭 Activity)。
  4. onDestroy()
  • 触发时机: Activity 即将被销毁已完成销毁时调用。这可能发生在:
    • 用户显式关闭 Activity(如按返回键)。
    • 在 Activity 处于 Stopped 状态且系统需要回收内存时被系统终止。
    • 由于配置变更(如屏幕旋转、语言更改)系统临时销毁该 Activity 实例(紧接着会创建一个新的实例)。
  • 主要职责:
    • 执行最终的清理工作(如注销全局监听器、释放可能泄漏的资源)。
    • 确保所有在 onCreate() 中创建并长期运行的操作(如网络请求)被取消或清理。
    • 区分是永久销毁还是配置变更导致的临时销毁(检查 isFinishing())。
  1. onRestart()
    • 在 Activity 从 Stopped 状态重新回到 Started 状态之前调用(即在 onStart() 之前)。
    • 用于执行仅在 Activity 从停止状态恢复时才需要的特殊初始化(不同于首次创建的初始化)。

下图是 Android 官方提供的一张活动生命周期示意图:

在这里插入图片描述

这七种方法除了 onRestart() 方法,其他都是两两相对的,从而又可将活动分为 3 种生存期:

  1. 完整生存期
    • 范围onCreate()onDestroy()
    • 核心特点
      • 覆盖 Activity 从创建到销毁的完整过程
      • onCreate() 完成全局初始化(布局、数据绑定等)
      • onDestroy() 执行最终清理(释放内存、关闭连接等)
  2. 可见生存期
    • 范围onStart()onStop()
    • 核心特点
      • Activity 对用户可见的整个阶段
      • 包括前台(可交互)和后台(被部分遮挡)状态
      • 资源管理原则:可见时加载,不可见时释放
  3. 前台生存期
    • 范围onResume()onPause()
    • 核心特点
      • Activity 处于栈顶且可交互的状态
      • 用户直接操作的黄金时期
      • 响应速度要求最高(禁止耗时操作)

《第一行代码》原文:

Activity 类中定义了 7 个回调方法,覆盖了活动生命周期的每一个环节,喜爱按就来一一介绍这 7 个方法。

  • onCreate()它会在活动第一次创建的时候调用。应该在这个方法中完成活动的初始化操作,比如加载布局、绑定事件等。
  • onStart()这个方法在活动由不可见变为可见的时候调用。
  • onResume()这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。
  • onPause()这个方法在系统准备去启动或者恢复另一个活动的时候调用。通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。
  • onDestory()这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。
  • onRestart()这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。

以上 7 个方法除了 onRestart() 方法,其他都是两两相对的,从而又可将活动分为 3 种生存期。

  • 完整生存期

    活动在 onCreate() 方法和 onDestroy() 方法之间所经历的就是完整生存期。一般情况下,一个活动会在 onCreate() 方法中完成各种初始化操作,而在 onDestroy() 方法中完成释放内存的操作。

  • 可见生存期

    活动在 onStart() 方法和 onStop() 方法之间所经历的就是可见生存期。 在可见生存期内,活动对于用户总是可见的,即便有可能无法和用户进行交互。我们可以通过这两个方法,合理地管理那些对用户可见的资源。比如在 onStart() 方法中对资源进行加载,而在 onStop() 方法中对资源进行释放,从而保证处于停止状态的活动不会占用过多内存。

  • 前台生存期

    活动在 onResume() 方法和 onPause() 方法之间所经历的就是前台生存期。 在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行交互的,我们平时看到和接触最多的也就是这个状态下的活动。

Activity 生命周期回调方法总结

回调方法触发时机核心用途下一状态
onCreate()Activity 首次创建时调用1. 初始化基本组件 2. 调用 setContentView() 绑定布局 3. 初始化数据(如 ViewModel)onStart()
onStart()Activity 对用户可见时1. 注册与可见性相关的监听器 2. 准备前台显示所需资源onResume() 或 onStop()
onResume()Activity 进入前台并获得焦点1. 启动用户交互组件(如动画、传感器) 2. 刷新 UI 数据onPause()
onPause()Activity 失去焦点但仍部分可见1. 释放独占资源(如相机) 2. 提交轻量级数据保存onResume() 或 onStop()
onStop()Activity 完全不可见时1. 释放所有可见性相关资源 2. 保存重要数据到持久存储 3. 调用 onSaveInstanceState()onRestart() 或 onDestroy()
onRestart()Activity 从停止状态重新显示前执行恢复可见时的特殊初始化onStart()
onDestroy()Activity 销毁前(永久或临时)1. 清理所有资源 2. 终止后台任务 3. 区分 isFinishing()

:以上所有方法均可通过重写(@Override)在自定义 Activity 中实现。

3.2 演示 Activity 的生命周期

以下是一个简单的 Android 活动生命周期演示代码,通过日志输出清晰展示各个生命周期方法的触发时机:

import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {// 日志标签private static final String TAG = "LifecycleDemo";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d(TAG, "onCreate - 活动被创建");// 添加关闭按钮点击事件findViewById(R.id.close_button).setOnClickListener(v -> {Log.d(TAG, "用户点击关闭按钮");finish(); // 结束活动});}@Overrideprotected void onStart() {super.onStart();Log.d(TAG, "onStart - 活动可见");}@Overrideprotected void onResume() {super.onResume();Log.d(TAG, "onResume - 活动可交互");}@Overrideprotected void onPause() {super.onPause();Log.d(TAG, "onPause - 活动失去焦点");}@Overrideprotected void onStop() {super.onStop();Log.d(TAG, "onStop - 活动不可见");}@Overrideprotected void onRestart() {super.onRestart();Log.d(TAG, "onRestart - 活动重新启动");}@Overrideprotected void onDestroy() {super.onDestroy();Log.d(TAG, "onDestroy - 活动被销毁");}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"android:padding="16dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="活动生命周期演示"android:textSize="20sp"android:textStyle="bold"/><TextViewandroid:id="@+id/lifecycle_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="查看Logcat中的生命周期日志"android:textSize="18sp"android:layout_marginTop="24dp"/><Buttonandroid:id="@+id/close_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="关闭活动"android:layout_marginTop="24dp"/></LinearLayout>

初始启动应用

在这里插入图片描述

按下返回键

在这里插入图片描述

点击“关闭活动”按钮

在这里插入图片描述

按下 Home 键返回桌面

在这里插入图片描述

从最近任务重新打开应用

在这里插入图片描述

旋转屏幕(测试配置变更)

在这里插入图片描述

4. Activity的启动模式

Android 的活动启动模式决定了活动实例如何与任务栈交互,是 Android 系统管理活动实例的重要机制,在实际项目中我们应根据特定的需求为每个活动指定恰当的启动模式。启动模式一共有四种:standard、singleTop、singleTask 和 singleInstance,可以在 AndroidManifest.xml 中通过给<activity>标签指定 android:launchMode 属性来选择启动模式。

示例代码:

<activityandroid:name=".MainActivity"android:exported="true"android:launchMode="singleTop">

4.1 standard(标准模式)

《第一行代码》原文:

standard 是活动默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式。因此,到目前为止我们写过的所有活动都是使用的standard模式。经过上一节的学习,你已经知道了 Android 是使用返回栈来管理活动的,在standard模式(即默认情况)下,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用 standard 模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。

  • 默认模式,每次启动活动都会创建新实例。
  • 新实例被压入启动它的任务栈栈顶
  • 适用场景:普通活动,需要多个实例的情况

在这里插入图片描述

4.2 singleTop(栈顶复用模式)

《第一行代码》原文:

可能在有些情况下,你会觉得 standard 模式不太合理。活动明明已经在栈顶了,为什么再次启动的时候还要创建一个新的活动实例呢?别着急,这只是系统默认的一种启动模式而已,你完全可以根据自己的需要进行修改,比如说使用 singleTop 模式。当活动的启动模式指定为 singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。

  • 如果目标活动已在栈顶,则复用实例(调用onNewIntent()
  • 不在栈顶则创建新实例
  • 适用场景:防止重复创建栈顶活动(如通知跳转)

在这里插入图片描述

4.3 singleTask(栈内复用模式)

《第一行代码》原文:

使用 single Top 模式可以很好地解决重复创建栈顶活动的问题,但是正如你在上一节所看到的,如果该活动并没有处于栈顶的位置,还是可能会创建多个活动实例的。那么有没有什么办法可以让某个活动在整个应用程序的上下文中只存在一个实例呢?这就要借助 single Task 模式来实现了。当活动的启动模式指定为singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。

  • 系统会寻找匹配的任务栈(由taskAffinity决定)
  • 如果存在实例,则清除其上的所有活动并调用onNewIntent()
  • 不存在则创建新实例
  • 适用场景:应用入口活动(如主界面)

在这里插入图片描述

4.4 singleInstance(单实例模式)

《第一行代码》原文:

singleInstance 模式应该算是 4 种启动模式中最特殊也最复杂的一个了,你也需要多花点功夫来理解这个模式。不同于以上 3 种启动模式,指定为 singleInstance 模式的活动会启用一个新的返回栈来管理这个活动(其实如果singleTask 模式指定了不同的taskAffinity,也会启动一个新的返回栈)。那么这样做有什么意义呢?想象以下场景,假设我们的程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现呢?使用前面 3 种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用 singleInstance 模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。

  • 活动独占一个任务栈
  • 全局唯一实例
  • 后续启动直接复用该实例
  • 适用场景:需要全局共享的活动(如来电界面)

在这里插入图片描述

  • taskAffinity: 这个属性通常与 singleTasksingleInstance 结合使用,用于指定 Activity 希望归属的任务栈的名称(默认为应用包名)。它影响 singleTask 寻找或创建哪个专属栈,以及 Intent 标志 FLAG_ACTIVITY_NEW_TASK 的行为。
  • onNewIntent(): 对于复用实例的模式 (singleTop, singleTask, singleInstance),当复用发生时,新的 Intent 是通过 onNewIntent() 方法传递的,而不是 onCreate()务必在此方法中处理新的意图数据

4.5 使用 Intent Flags

启动模式也可以动态指定,优先级高于清单中声明:

Intent intent = new Intent(this, TargetActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

常用标志

标志说明
FLAG_ACTIVITY_NEW_TASK在新任务中启动 Activity
FLAG_ACTIVITY_SINGLE_TOP等同于 singleTop
FLAG_ACTIVITY_CLEAR_TOP清除目标 Activity 之上的所有 Activity
FLAG_ACTIVITY_CLEAR_TASK在启动前清除整个任务的所有 Activity
FLAG_ACTIVITY_REORDER_TO_FRONT如果 Activity 已存在,将其移到栈顶
http://www.lryc.cn/news/574119.html

相关文章:

  • SAP将指定EXCEL工作SHEET的数据上传到内表
  • 基于 BERT 与语义角色标注的细粒度中文仇恨言论检测
  • 剑指offer40_数字序列中某一位的数字
  • 中国风国潮通用PPT模版
  • 【项目管理】项目管理资料文档模板(ZIP,PPT,WORD)
  • 榕壹云无人售货机管理系统:开源架构赋能私有化部署,打造智能零售技术解决方案
  • AI 领航设计模式学习:飞算 JavaAI 解锁单例模式实践新路径
  • 在测试中,如何判断是前端 Bug 还是后端 Bug?
  • 错误: 程序包androidx.fragment.app不存在 import android
  • 实现 el-table 中键盘方向键导航功能vue2+vue3(类似 Excel)
  • Flutter ListTile 徽章宽度自适应的真正原因与最佳实践
  • iOS 为图片添加水印
  • 基于openfeign拦截器RequestInterceptor实现的微服务之间的夹带转发
  • react快速开始项目模板
  • Web基础 -SpringBoot入门 -HTTP-分层解耦 -三层架构
  • Protobuf 深度解析:从基础语法到高级应用
  • 【目标检测】图像处理基础:像素、分辨率与图像格式解析
  • “自动化失败归因”测试集-WhoWhen
  • 在大数据求职面试中如何回答分布式协调与数据挖掘问题
  • 云原生 CAD 让制造业设计协同更便捷
  • 3D模式格式转换工具HOOPS Exchange如何将3D PDF转换为STEP格式?
  • 【实时Linux实战系列】使用定时器实现定时任务
  • 计算机网络:(六)超详细讲解数据链路层 (附带图谱表格更好对比理解)
  • docker镜像中集成act工具
  • 刀客doc:阿里巴巴集团品牌部划归集团公关管理
  • Java基础(三):逻辑运算符详解
  • P3258 [JLOI2014] 松鼠的新家
  • (LeetCode 面试经典 150 题) 27.移除元素
  • PR出书启动
  • ✨通义万相2.1深度解析:AI视频生成引擎FLF2V-14B全流程指南(命令行参数+模型架构+数据流)