Android小进阶——Activity生命周期和启动模式

本文围绕Activity展开,介绍了其生命周期,包括典型情况(如onCreate、onStart等方法触发时机)和异常情况(资源配置改变、内存不足);启动模式,可通过清单文件(如standard、singleTop等四种模式)或Intent标志定义;还阐述了后台堆栈模型,活动按后进先出规则操作,系统会保留停止活动的UI状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

  1. Activity生命周期
  • 典型情况
  • 异常情况
  1. 启动模式.
  • 清单文件中的launchModel
  • Intent中的Flags
  1. 后台堆栈模型

正文

(一)生命周期

典型情况下的生命周期

(1)onCreate()
在系统创建活动时触发;一般在这里做一些初始化的工作,比如调用setContentView去加载界面布局资源、初始化Activity所需数据等。

(2)onStart()
作为onCreate()退出时,活动进入开始状态,但还无法和用户进行交互,可以理解为Activity已经显示出来了,但我们还看不到

(3)onResume()
当一个活动和用户发生交互的时候,触发该方法。此时,activity位于activity堆栈的顶部,并捕获所有用户输入。应用程序的大多数核心功能是在此方法中实现的。

(4)onPause()
活动失去焦点并进入暂停状态时,系统会调用。例如当用户点击“后退”或“最近”按钮时,会出现此状态。
当系统调用此方法时,通常表示用户正在离开此activity(文档中表示为partially visable,也就是部分可见),并将很快进入“已停止”或“已恢复”状态。此时可以做一些存储数据、停止动画等工作,但不能太耗时。

你不应该在此方法中保存应用程序或用户数据,进行网络通话,或执行数据库事务。
一旦onPause()完成执行,下一个回调是onStop()或onResume(),视activity进入暂停状态后发生的情况而定。

(5)onStop()
当活动不再对用户可见时调用。
此方法被调用的情况有:activity正在被破坏,新activity正在开始,或现有activity正在进入恢复状态并且覆盖已停止的活动。可以做一些稍微重量级的回收工作,同样不能太耗时。如果内存紧张,系统会直接结束这个活动,而不会触发 onStop 方法

(6)onRestart()
当处于“已停止”(Stop)状态的activity即将重新启动时,系统将调用此方法。此回调始终紧跟着onStart()后发生。

(7)onDestory()
此方法在销毁activity之前被调用。通常实现以确保在activity或包含它的进程被销毁时释放所有活动的资源。

生命周期图
附加说明
(1)针对一个特定的Activity,第一次启动回调为:onCreate -> onStart -> onResume
(2)当用户打开一个新的Activity或者切换到桌面时(桌面其实也是一个Activity,运行在单独的栈中),回调如下:onPause -> onStop(这也是为什么不能在这两个方法做耗时操作的原因,因为要快速显示新Activity)。有一个特殊情况,若新Activity采用了透明主题,那么onStop不会被调用。
(3)当用户再次回到原Activity时,回调为:onRestart -> onStart -> onResume。
(4)当用户按back键回退时,回调为:onPause -> onStop -> onDestory
(5)假设从当前Activity中打开一个新Activity,那么当前Activity的onPause执行,然后新Activity会执行(1)中的回调

异常情况下的生命周期

这里介绍两种情况:资源相关的系统配置发生改变时和系统内存不足时。

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

系统配置发生改变的情况有挺多种,其中比较常见的有:横竖屏切换、切换了系统语言、键盘调出与消失、连接到了外部显示设备等。在默认情况下,Activity会被销毁并且重新创建,这个过程是:
第一步:Activity会被销毁,onPause、onStop、onDestory均会被调用,并且由于是在异常情况下被终止的,所以还会调用onSaveInstanceState(Bundle)来保存当前Activity的状态
第二步:Activity被重新创建后,系统会调用onRestoreInstanceState,并且获得销毁时保存在onSaveInstanceState里的Bundle对象,从而取出Activity的状态信息进行重建。(从时序上来说,onRestoreInstanceState在onStart之后被调用)

Activity的状态:听起来有些抽象,具体一点就是文本框中用户输入的内容,ListView滚动的位置等View相关的状态信息,系统都会在Activity被异常销毁时帮我们重建。实现方法就是在这些View组件覆写那两个回调方法,各自保存和恢复自己的状态信息。

(2)系统内存不足时导致低优先级的Activity被杀死
先描述一下Activity的优先级,从高到低分为三级:
(1)前台Activity——正在和用户交互的Activity,优先级最高。
(2)可见但非前台Activity——比如Activity中弹出了一个对话框,导致Activity可见但无法与用户直接交互。
(3)后台Activity——暂停了的Activity,比如执行了onStop的Activity,优先级最低。

当系统内存不足时,会按照优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据,这个过程和上一种异常终止情况完全一致。

(二)启动模式

启动模式允许您定义活动的新实例与当前任务堆栈的关联方式
堆栈是用来保存Activity实例的栈容器,默认情况下,一个应用初始化就会有一个堆栈放着MainActivity(堆栈的id一般是包名),当创建了新的活动实例后就把该实例压入栈中,每按一下back键就会有一个Activity出栈,直到栈空为止。当栈中无任何Activity的时候,系统就会回收这个任务栈。

桌面系统也是一个堆栈,每个进程创建的时候会有一个新的堆栈,一个进程中可以有多个堆栈

您可以通过两种方式定义不同的启动模式:使用清单文件或使用Intent标志。(Intent标志的优先级高一些)

使用清单文件定义启动模式:

在清单文件中声明活动时,可以使用 元素的android:launchMode属性指定活动应如何与任务关联。其有四种不同的启动模式:

  • standard” (默认模式):系统在启动它的任务中创建活动的新实例,并将意图路由到该实例。活动可以多次实例化,每个实例可以属于不同的任务,一个任务可以有多个实例。

  • singleTop”:栈顶复用模式。若activity的实例已存在于当前任务堆栈顶部(也就是当前活动),则系统通过调用onNewIntent()方法将Intent路由到该实例,而不是创建activity的新实例;反之则和standard模式一样。

  • singleTask”:栈内复用模式
    第一步:每次启动该活动时系统首先会寻找是否存在活动想要的任务栈,如果不存在就重新创建该任务栈,然后创建活动实例并将其压入该栈中;
    第二步:如果存在想要的任务栈,先在返回栈中检查是否存在该活动的实例, 如果发现已经存在则直接使用该实例, 并把在这个活动之上的所有活动统统出栈(clear top效果,Intent的Flag之一), 如果没有发现就会创建一个新的活动实例并压入栈中。

  • singleInstance”:单实例模式。可以说是加强版singleTask模式,除了具有singleTask模式的所有特性之后,还加强了一点,就是具有此模式的Activity只能单独地位于一个任务栈中。举个例子,比如Activity A是此模式,当A启动后,系统会为它新建一个任务栈,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了(也就是A被back了)。

对singleTask的解释
在singleTask第一步的时候提到了“想要的任务栈”,那么肯定有一个参数来指定这个任务栈,它就是:TaskAffinity(也是 的一个属性,是一个字符串)。默认情况下,所有Activity所需的任务栈的名字为应用的包名,不需要我们显式声明。当使用singleTask模式时,一般都会为其指定TaskAffinity属性(不然第一步就相当于直接跳过了)。

TaskAffinity还可以和activity的另一个属性allowTaskReparenting配对使用,情况会比较复杂。

实例

用三个实际例子来说明以上四种启动模式:

  1. 假设任务的后台堆栈由根活动A组成,其中活动B,C和D位于顶部(堆栈为ABCD; D位于顶部)。意图到达类型D的活动。如果D具有默认"standard"启动模式,则启动该类的新实例并且堆栈变为ABCDD。但是,如果D的启动模式是"singleTop",D的现有实例接收意图onNewIntent(),因为它位于堆栈的顶部 - 堆栈仍然是ABCD。但是,如果意图到达类型B的活动,则将新的B实例添加到堆栈中,即使其启动模式为"singleTop"。

  2. 现在有三个Activity,清单文件中的定义如下所示。注意到除了MainActivity外,其他两个Activity都指定了singleTask和相同的TaskAffinity。

        <activity
            android:name="com.ryg.chapter_1.MainActivity"
            android:configChanges="orientation|screenSize"
            android:label="@string/app_name"
            android:launchMode="standard" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.ryg.chapter_1.SecondActivity"
            android:configChanges="screenLayout"
            android:label="@string/app_name"
            android:launchMode="standard"
            android:taskAffinity="com.ryg.task1" />
        <activity
            android:name="com.ryg.chapter_1.ThirdActivity"
            android:configChanges="screenLayout"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:taskAffinity="com.ryg.task1" >

那么从MainActivity启动SecondActivity,在SecondActivity中启动ThirdActivity,然后在ThirdActivity中又启动MainActivity,最后在MainActivity中启动SecondActivity,现在按两次back键,然后我们会看到哪个Activity呢?答案是桌面!
下面我们将这三个Activity分别称为A、B、C。MainActivity,也就是A,它在初始堆栈1里(名字是包名)。A启动B,由于B是singleTask并且指定了不一样的堆栈2,那么会创建这个堆栈并把B实例放进去;B中启动C,由于是相同的TaskAffinity会直接将C实例压入栈2,此时在C中启动A,由于A是standard模式,很简单地直接将实例A压入创建它的Activity所在栈,也就是栈2.
这时,在栈1中存在A,栈2中存在BCA,这时在A中启动B,由于栈2中有B的实例,根据Clear Top特性,栈2会将A、C依次出栈,以将B放在栈顶。这样,按下第一次back键后,栈2中唯一一个Activity被出栈,栈2被销毁,再按一次back键,就轮到栈1中唯一一个Activity了,再出栈也就到了桌面了。

  1. 有三个Activity,分别为First,Second,Third,特意为Second指定启动模式为"singleInstance",在每个Activity里都打印出自己所在堆栈的id(getTaskId()),测试从First启动Second,然后从Second启动Third,发现First和Third在同一个栈,而Second在另一个栈。此时从Third回退会回到First而不是Second,再回退才会到Second。示意图如下:
    示意图
使用Intent标志定义启动模式

启动活动时,您可以通过在传递到的intent中包含标志来修改活动与其任务的默认关联。您可以用来修改默认行为的标志是:

  • FLAG_ACTIVITY_NEW_TASK:与singleTask相同。
  • FLAG_ACTIVITY_SINGLE_TOP:与singleTop相同。
  • FLAG_ACTIVITY_CLEAR_TOP:如果正在启动的活动已在当前任务中运行,则不会启动该活动的新实例,而是销毁其上的所有其他活动,并将此意图传递给活动的恢复实例(现在在顶部的)。launchMode没有此值。FLAG_ACTIVITY_CLEAR_TOP最常与 FLAG_ACTIVITY_NEW_TASK共同使用。当一起使用时,这些标志是一种在另一个任务中定位现有活动并将其置于可以响应意图的位置的方法。
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

(三)后台堆栈模型

  • 当前活动开始另一个活动时,新活动将被推到堆栈顶部并获得焦点。之前的活动仍在堆栈中,但已停止。**当活动停止时,系统将保留其用户界面的当前状态。**当用户按下“ 返回” 按钮时,当前活动将从堆栈顶部弹出(活动被销毁),之前的活动将恢复(其UI的先前状态将恢复)。堆栈中的活动永远不会重新排列,只能在当前活动启动时从堆栈中推送并弹出到堆栈中,并在用户使用Back退出时弹出按钮。因此,后堆栈作为“后进先出”对象结构操作。图1显示了这种行为,时间轴显示了活动之间的进度以及每个时间点的当前后栈。任务堆栈

注意:可以在后台同时保存多个任务。但是,如果用户同时运行许多后台任务,系统可能会开始销毁后台活动以恢复内存,从而导致活动状态丢失。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值