【Android】深入理解Activity的生命周期和IntentFilter

【Android】深入理解Activity的生命周期和IntentFilter

文章目录

  • 【Android】深入理解Activity的生命周期和IntentFilter
    • [1. Activity的生命周期](#1. Activity的生命周期)
      • [1.1 典型情况下的生命周期分析:](#1.1 典型情况下的生命周期分析:)
      • [1.2 异常情况下的生命周期分析](#1.2 异常情况下的生命周期分析)
        • [1.2.1 资源相关的系统配置发生改变导致Activity被杀死并重新创建](#1.2.1 资源相关的系统配置发生改变导致Activity被杀死并重新创建)
        • [1.2.2 资源内存不足导致低优先级的Activity被杀死](#1.2.2 资源内存不足导致低优先级的Activity被杀死)
    • [2. 活动的启动模式](#2. 活动的启动模式)
    • [3. IntentFilter的匹配规则](#3. IntentFilter的匹配规则)
      • [3.1 Action的匹配规则](#3.1 Action的匹配规则)
      • [3.2 Category的匹配规则](#3.2 Category的匹配规则)
      • [3.3 Data的匹配规则](#3.3 Data的匹配规则)

1. Activity的生命周期

Android中的活动是层叠的,每当我们启动一个新活动,就会覆盖之前的活动。当我们按下back键将当前活动销毁后,之前的活动又会再一次展现出来。而Android是通过任务(Task)来管理活动的,一个任务就是存放在栈里边的活动的集合。这个栈也被称作返回栈(Back Stack)。

Activity在进栈与出栈的过程中国,一般意义上有四种状态:

  1. 当Activity处于栈顶时,此时正好处于屏幕最前方,此时处于运行状态
  2. 当Activity失去了焦点但仍然部分可见(如栈顶的Activity是透明的或者栈顶Activity并不是铺满整个手机屏幕),此时处于暂停状态
  3. 当Activity被其他Activity完全遮挡,此时此Activity对用户不可见,此时处于停止状态
  4. 当Activity由于人为或系统原因(如低内存等)被销毁,此时处于销毁状态

1.1 典型情况下的生命周期分析:

在正常情况下,Activity会经历如下生命周期:

  1. onCreat():当Activity第一次被创建时调用,完成活动的初始化操作。
  2. onStart():表示Activity正在被启动,即将开始。这时Activity已经可见了,但还没有出现在前台,无法和用户交互。
  3. onResume():表示Activity已经可见了,并且出现在前台并开始活动。
  4. onPause():表示Activity正在停止,正常情况下,紧接着onStop就会被调用。
  5. onStop():表示Activity即将停止,当Activity完全不可见时调用。
  6. onDestory():Activity被销毁时调用。
  7. onRestart():表示Activity正在重新启动,在Activity由停止状态变为运行状态时调用。

注:

  1. onResume()onStart()的区别:onStart()和onResume()都表示Activity已经可见,但是onStart()的时候Activity还在后台,onResume的时候才显示到前台。
  2. 当启动一个新Activity时,一定是老活动的onPause方法先执行,新活动的onResume才会执行。
  3. 在onPause和onStop方法中进行的资源回收工作不能太耗时。
Activity的3种生存期
  1. **完整生命周期:活动在 onCreat()方法和onDestory()**方法之间所经历的,就是完整生命周期。一般情况下,活动会在onCreate()方法中完成各种初始化,在onDestory()方法中完成资源释放的操作。
  2. 前台生命周期:活动在onResume()方法和onPause()方法之间所经历的就是前台生命周期。在前台生命周期内,活动总是处于运行状态,此时的活动可以和用户进行交互。
  3. 可视生命周期:活动在onStart()方法和onStop()方法之间所经历的,就是可视生命周期。在可视生命周期内,活动对于用户时可见的,但可能与用户无法交互。
Activity的启动流程

主要包含以下几个部分:

  1. 发起者进程:当前正在前台的应用进程。
  2. 系统进程:Android系统的核心,运行着关键系统服务,特别是ActivityTaskManagerService(ATMS),负责协调和调度整个流程。
  3. Zygote进程:所有应用进程的"孵化器",预加载了通用框架和资源,用于快速构建出新应用进程。
  4. 目标进程 :将要启动的Activity所在的应用进程。它内部运行着:
    • ActivityThread:应用的主线程,是每个应用的真正入口。负责接收系统服务(ATMS)的指令,并调用相应的Activity生命周期方法。
    • Instrumentation:负责创建Activity实例和调用生命周期方法。每个应用只有一个Instrumentation实例。
    • Activity:最终要启动的目标对象。

主要过程:

  1. 发起请求 :Activity A调用 startActivity(),请求通过Binder IPC发送到系统进程(ATMS)。
  2. 系统调度:ATMS解析Intent、校验权限。如果目标应用进程不存在,则请求Zygote进程构建一个新进程。
  3. 进程准备:新进程创建后,初始化主线程(ActivityThread)并通知ATMS,建立通信链路。
  4. 执行指令 :ATMS通过Binder通知目标进程的 ActivityThread启动目标Activity。
  5. 创建与回调 :目标进程的主线程通过Handler消息,使用 Instrumentation工具类反射创建Activity实例 ,并依次同步调用其生命周期方法:onCreate()-> onStart()-> onResume()
  6. 界面渲染 :在 onResume()之后,将Activity的根视图(DecorView)添加到 WindowManager,最终界面显示出来。

1.2 异常情况下的生命周期分析

1.2.1 资源相关的系统配置发生改变导致Activity被杀死并重新创建

最常见的异常生命周期场景就是配置变更 ,比如屏幕旋转、键盘可用性改变、语言切换等。这会导致Activity被销毁并重建。生命周期如下图:

  • onSaveInstanceState(Bundle outBundle) :在Activity即将被异常销毁前(在onStop之前,可能在onPause前后)调用。需要将希望恢复的数据(如编辑框的临时内容、游戏分数)存入Bundle中。这个方法不会在用户主动销毁(如按返回键)时调用。
  • onRestoreInstanceState(Bundle savedInstanceState) :在Activity被异常销毁后重建时,在onStart之后被调用,用于恢复数据。你也可以在onCreate中恢复数据,但onRestoreInstanceState被调用时,视图层级已经创建完成,有时更方便。
1.2.2 资源内存不足导致低优先级的Activity被杀死

Activity按照优先级从低到高,可以分为以下3种:

  1. 前台Activity:正在和用户交互的Activity,优先级最高。
  2. 可见但非前台Activity:比如Activity中弹出了一个对话框,导致Activity可见但是位于后台无法和用户进行直接交互。
  3. 后台Activity:已经被暂停的Activity,比如执行了onStop,优先级最低。

当系统内存不足时,系统就会按照上述优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceStateonRestoreInstanceState来存储和恢复数据。

生命周期表现 :如果是后台Activity被杀,则此时没有任何生命周期回调,onDestory不会被调用。如果用户返回该Activity,如果此时进程还存活,系统会直接调用前台Activity的onRestart-> onStart-> onResume。如果进程已被系统杀死:系统会重新创建进程,并尝试重建任务栈顶的Activity(即用户上次看到的那个)。此时的生命周期与屏幕旋转类似:

  1. onCreate(savedInstanceState)- 这里的savedInstanceState是系统在杀死进程前,自动调用所有Activity的onSaveInstanceState保存下来的一个Bundle(称为"墓碑"状态)。
  2. 之后是 onStart, onRestoreInstanceState, onResume

2. 活动的启动模式

  1. standard(标准模式)默认模式 。每次启动都创建一个新实例
  2. singleTop(栈顶复用) :如果要启动的Activity正好在栈顶 ,则直接复用,不会新建。否则,创建新实例。
  3. singleTask(栈内单例) :在整个任务栈中只保留一个实例 。如果已存在,则清空它上面的所有Activity,让它回到栈顶。
  4. singleInstance(全局单例) :最特殊。让Activity独占一个全新的任务栈,并且该栈中只有它一个Activity。

3. IntentFilter的匹配规则

IntentFilter即"意图过滤器",只有IntentFilter中的action,category,data都匹配时,才能成功启动目标Activity。另外,一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。比如下面的例子:

xml 复制代码
<activity android:name=".TargetActivity">
    <intent-filter>
        <action android:name="com.example.action.MY_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

在另一个活动中发起Intent:

java 复制代码
Intent intent = new Intent();
intent.setAction("com.example.action.MY_ACTION");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType("text/plain");

startActivity(intent);

可以看到,三个规则都会成功匹配,所以最后可以成功启动TargetActivity。

3.1 Action的匹配规则

Intent 中指定的 Action 字符串,必须出现在 Filter 声明的 Action 列表中。Intent只能通过 intent.setAction(String)设置一个 Action。而Filter可以通过多个 <action>标签声明多个 Action。只要 Intent 的 Action 与 Filter 中声明的任意一个 Action 字符串完全相等,则 Action 匹配成功。

需要注意的是,如果 Intent 没有设置 Action,则自动匹配失败。第二,如果 Filter 没有声明任何 Action,则只能匹配没有设置 Action 的 Intent。

使用示例如下:

xml 复制代码
<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <action android:name="com.example.action.MY_CUSTOM_ACTION" />
</intent-filter>
java 复制代码
intent.setAction("android.intent.action.VIEW"); // 匹配成功(与第一个action匹配)
intent.setAction("com.example.action.MY_CUSTOM_ACTION"); // 匹配成功(与第二个action匹配)
intent.setAction("some.other.action"); // 匹配失败

3.2 Category的匹配规则

Intent 中携带的每一个 Category,都必须能在 Filter 声明的 Category 列表中找到。和Action不同的是,Intent可以通过 intent.addCategory(String)添加多个 Category。Filter也可以通过多个 <category>标签声明多个 Category。当Intent 中所有的 Category 在 Filter 中有声明,即 Intent 的 Category 集合是 Filter 的 Category 集合的子集时,匹配成功。Filter 声明的 Category 可以比 Intent 携带的更多。

注: CATEGORY_DEFAULT通过 startActivity()发起的隐式 Intent,系统会自动为其加上 android.intent.category.DEFAULT这个 Category。因此,如果 Activity 希望被隐式 Intent 启动,必须在 Filter 中声明 <category android:name="android.intent.category.DEFAULT" />,否则永远无法匹配。

比如,

xml 复制代码
<intent-filter>
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

intent设置时,系统会自动添加 CATEGORY_DEFAULT:

java 复制代码
intent.addCategory(Intent.CATEGORY_DEFAULT); // 匹配成功
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addCategory(Intent.CATEGORY_BROWSABLE); // 匹配成功
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addCategory("com.example.category.CUSTOM"); // 匹配失败(CUSTOM不在Filter的声明中)

3.3 Data的匹配规则

Data 由两部分组成:URIMIME 类型

Intent 的 Data 必须满足 Filter 中声明的某一项 <data>规则。比如:

xml 复制代码
<data android:scheme="http" 
android:host="example.com" 
android:mimeType="text/plain"/>

这个标签实际上定义了一组条件:Scheme 必须是 http,Host 必须是 example.com,且 MIME 类型必须是 text/plain。

匹配过程如下:

系统首先会比较 MIME Type(MIME Type 优先)。如果 Filter 声明了 mimeType,则 Intent 的 Type 必须与之匹配(支持通配符)。如果 MIME Type 匹配或者 Filter 未声明 MIME Type,则开始匹配 URI。URI 的匹配是逐级进行的:

  • Scheme(协议,如 http、content、file):必须完全匹配。
  • Host (主机名,如 www.example.com):必须完全匹配,支持通配符 *
  • Port(端口,如 8080):必须完全匹配。如果未指定,则使用 Scheme 的默认端口。
  • Path (路径,如 /images/logo.png):可以完全匹配,也可以使用通配符 *进行前缀匹配。

举例说明一下:

xml 复制代码
<intent-filter>
    <!-- 规则1 -->
    <data android:scheme="content" android:mimeType="video/*"/> 
    <!-- 规则2 -->
    <data android:scheme="http" android:host="*.example.com" android:pathPrefix="/movies"/> 
</intent-filter>
java 复制代码
intent.setDataAndType(Uri.parse("content://media/videos/1"), "video/mp4"); // 匹配成功(scheme和mimeType都匹配规则1)

intent.setDataAndType(Uri.parse("http://foo.example.com/movies/avatar.mp4"), null); // 匹配成功(scheme, host, path都匹配规则2)

intent.setDataAndType(Uri.parse("http://google.com"), "text/html"); // 匹配失败(host不匹配规则2,scheme和mimeType不匹配规则1)
相关推荐
李新_10 小时前
基于Markwon封装Markdown组件
android·aigc·markdown
java1234_小锋10 小时前
Spring IoC的实现机制是什么?
java·后端·spring
xqqxqxxq11 小时前
背单词软件技术笔记(V2.0扩展版)
java·笔记·python
消失的旧时光-194311 小时前
深入理解 Java 线程池(二):ThreadPoolExecutor 执行流程 + 运行状态 + ctl 原理全解析
java·开发语言
哈哈老师啊11 小时前
Springboot学生综合测评系统hxtne(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·数据库·spring boot
4311媒体网11 小时前
帝国cms调用文章内容 二开基本操作
java·开发语言·php
zwxu_12 小时前
Nginx NIO对比Java NIO
java·nginx·nio
Non-existent98712 小时前
Flutter + FastAPI 30天速成计划自用并实践-第10天-组件化开发实践
android·flutter·fastapi
可观测性用观测云13 小时前
Pyroscope Java 接入最佳实践
java
气π14 小时前
【JavaWeb】——(若依 + AI)-基础学习笔记
java·spring boot·笔记·学习·java-ee·mybatis·ruoyi