Android——Activity生命周期与启动模式

本章主要介绍内容:
  • Android的生命周期分析
    • 典型情况下的生命周期分析
    • 异常情况下的生命周期分析
  • Activity的启动模式
    • Activity的LaunchMode
    • Activity的Flags
  • IntentFilter的匹配规则

Android的生命周期分析

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

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

  • onCreate :表示Activity正在被创建,这是生命周期的第一个方法,在这个方法中我们可以做一些初始化工作,比如调用setContentView去加载界面布局资源、初始化Activity所需要的数据
  • onRestart :表示Activity正在重新启动,一般情况下,当当前的Activity从不可见重新变为可见状态是,onRestart方法会被调用。这种情况一般是用户行为导致的,比如用户按Home键回到桌面或者用户新打开一个Activity,这时当前的Activity就会被暂停,也就是会执行onPause和onStop方法,接着用户又回到这个Activity,就会执行onRestart方法
  • onStart :表示Activity正在被启动,这时的Activity已经处于可见状态,但是并不具备和用户交互的能力。这个时候我们可以认为Activity已经显现出来了,只是我们还看不到
  • onResume :表示Activity已经可以看到了,并且已经具备了可以和用户交互的能力。这里需要注意和onStart方法的区别,onStart和onResume虽然都表示已经可见,但是onStart的时候其实Activity还在后台,而onResume的时候才是真正的处于前台
  • onPause :表示Activity正在停止,和OnResume对应,正常情况下当Activity处于不可见状态时,该方法会调用,而随后onStop方法会调用,在特殊情况下,如果这个时候快速的回到当前Activity,那么会直接跳过onStart方法直接调用onResume方法,这种情况属于极端情况,用户操作很难重现这一场景。在该方法中可以做一些存储数据、停止动画等不是太耗时的操作,因为这会影响到新的Activity的显示,只有在onPause方法执行完毕后onResume方法才会被执行
  • onStop :表示Activity即将停止,和onStart对应,和onPause方法一样可以用来做一些稍微重量级的回收工作,但是同样不能太耗时
  • onDestory :表示Activity即将被销毁,这是Activity生命周期中的最后一个方法,在这个方法中我们可以做一些回收工作和资源的释放

下面给出Activity的生命周期图:
这里写图片描述

典型情况下生命周期方法举例:

  • 针对上图,它的周期方法执行如下:
    • (1)第一次启动,会执行:onCreate –> onStart –> onResume
    • (2)当用户打开新的Activity时,生命周期方法回调如下: onPause –>onCreate –> onStart –> onResume –>onStop(上一个Activity的onStop)
    • (3)当用户打开一个新的Activity(该Activity采用了透明主题)时,生命周期方法回调如下: onPause –>onCreate –> onStart –> onResume 不会在调用上一个Activity的onStop方法
    • (4)当用户回到桌面时,生命周期方法回调如下:onPause –> onStop
    • (5)当用户再次回到原来的Activity时,生命周期方法回调如下:onRestart –> onStart – onResume
    • (6)当用户按back键回退到桌面时,生命周期方法回到如下:onPause –> onStop –> onDestory。
    • (7)当Activity被系统回收后,再次打开当前Activity,此时生命周期方法调用顺序和(1)一样,注意只是生命周期方法一样,不代表所以过程也一样
    • (8)从整个生命周期来说,onCreate和onDestory是配对的,分别标识者Activity的创建和销毁,并且只可能调用一次。从Activity是否可见来说,onStart和onStop是配对的,随着用户的操作或者设备的点亮和熄灭,这两个方法可能会被调用多次。从Activity是否存于前台来说,onResume和onPause是配对的,随着用户操作或者设备的点亮和熄灭,这两个方法可能会被调用多次。

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

  • 1、情况1:资源相关的系统配置发生改变导致的Activity被杀死并重新创建
    比如说:当前的Activity处于竖屏状态,如何突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity就会被销毁并且重新创建,当然我们也可以阻止系统重新创建我们的Activity。在默认情况下,如果我们的Activity不做任何处理,那么当我们的系统配置发生改变后,Activity就会被销毁并重新创建
其生命周期图:

这里写图片描述

当系统配置发生改变后,Activity会被销毁,其onPause、onStop、onDestory、方法均会被调用,由于Activity是在异常情况下终止的,系统会调用onSaveInstanceState方法来保存当前Activity的状态。这个方法的调用时机是在onStop之前,它和onPause没有既定的时序关系,它既可能在onPause执行前调用,也可能在onPause之后调用。需要强调一点的是,这个方法只会在Activity被异常终止的情况下,正常情况下系统不会调用这个方法。当Activity被重新创建后,系统会自动调用onRestoreInstanceState方法,并且把Activity销毁时onSaveInstanceState方法中所保留的Bundle对象作为参数同时传递给onRestoreInstanceState和onCreate方法。因此我们可以通过OnRestoreInstanceState和onCreate方法来判断Activity是否被重新创建了,如果被重新创建了,那么我们就可以取出之前保存的数据并恢复,从时序上来说,onRestoreInstanceState方法的调用时机在onStart方法之后

既然onRestoreInstanceState和onCreate这两个方法都可以用来做数据的恢复操作,那么他们两个方法有什么区别呢?

二者的区别:onRestoreInstanceState一旦被调用,其参数Bundle savedInstanceState一定是有值的,我们不用额外地判断是否为null;但是onCreate方法不行,onCreate如果是正常启动的情况下,其参数Bundle savedInstanceState一定为null;所以需要我们额外判断,所以在选择数据恢复时官方文档的建议是采用onRestoreInstanceState方法去恢复数据

关于横竖屏切换时生命周期的执行顺序以及处理方法请参照这两篇博客Activity 的生命周期 以及横屏竖屏切换时 Activity 的状态变化Android 屏幕旋转生命周期以及处理方法
  • 2、情况2:资源内存不足导致低优先级的Activity被杀死

之所以出现这种情况是因为:当系统内存不足时,系统会按照一种优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceState和onRestoreInstanceState方法来存储和恢复数据

而Android系统释放资源的优先顺序可以按照下面几种来依次进行释放:

1、空进程

这是Android优先杀死,因为此时该进程已经没有任何用途

2、后台进程

包含不可见的Activity,即跳转到其他Activity后,由于资源不足,系统会将原来的Activity杀死(即跳转的来源)

3、服务进程

即Service,当系统资源不足时,系统可能会杀掉正在执行任务的Service。因此在Service中执行比较耗时的操作,并不能保证一定会执行完毕

4、可见进程

当前屏幕上可以看到的Activity,例如显示一个对话框的Activity,那么对话框就变成了前台进程,而调用它的Activity是可见进程,并不属于前台

5、前台进程

当前处于最前端的Activity,也就是Android最后考虑杀死的对象。一般来说,前台进程Android系统是不会杀死的,只有在上面的四种进程都杀死后资源依旧不够的情况下才会考虑杀死前台进程。

Android的启动模式

Activity的LaunchMode

我们知道在默认情况下,当我们多次启动同一个Activity的时候,系统会创建多个实例并把它们一一放入任务栈中,当我们单击back键,会发现这些Activity会一一回退。任务栈是一种“后进先出”的栈结构,这个比较好理解,每按一下back键就会有一个Activity出栈,直到栈空为止,当栈中无任何Activity的时候,系统就会回收这个任务栈。
Activity的四种启动模式:
  • standard
  • singleTop
  • singleTask
  • singleInstance
standard

标准模式,也是系统默认模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的任务栈中。比如Activity A启动了Activity B(B是标准模式),那么B就会进入到A所在的任务栈中。

singleTop

栈顶复用模式。在这种模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前的请求的信息。需要注意的是,这个Activity的onCreate、onStart不会被系统调用,因为它并没有发生改变。如果新Activity的实例已经存在但不是处于栈顶位置,那么新的Activity仍然会被重新创建。举个例子:假设目前栈内的情况为 ABCD,其中 ABCD为四个Activity,A位于栈底,D位于栈顶,如果这个时候要再次启动D,而且D的启动模式为singleTop,那么栈内的情况依然是ABCD;如果这个时候我们要启动C,就算C的启动模式为singleTop,那么栈内的情况还是会发生改变 ABCDC

singleTask

栈内复用模式。和singleTop的区别是singleTask是一种单实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例。这就是singleTask的模式,如果发现所在的Activity栈中有对应的Activity的实例,则会使此Activity实例之上的其他Activity的实例全部出栈,使此Activity的实例位于栈顶,显示到前台。

举几个例子,当然例子的验证我们稍后会给验证代码:
1、比如目前任务栈S1中的情况为ABC,这个时候Activity D以singleTask模式请求启动,其所需要的任务栈(所需要的任务栈的概念稍后会给出)为S2,由于S2和D的实例均不存在,所以系统会先创建任务栈S2,然后在创建D的实例并将D入栈到S2。
2、另外一种情况,假设D所需要的任务栈为S1,其他情况如上面例子1所示,那么由于S1已经存在,所以系统会直接创建D的实例并将其入栈到S1.
3、如果D所需要的任务栈为S1,并且当前任务栈S1的情况为ADBC,根据栈内复用的原则,此时D不会在重新创建,系统会把D切换到栈顶并调用其onNewIntent方法,同时由于singleTask默认具有cleerTop的效果,会导致栈内所有在D上面的Activity全部出栈,于是最终S1中的情况为AD

singleInstance

单实例模式。这是一种加强的singleTask模式,他除了具有singTask模式的所有特性外,还加强了一点,那就是具有此种模式的Activity只能单独地位于一个任务栈中,换句话说,比如Activity A是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了

关于启动模式不了解的可以借鉴下这篇文章,这篇文章介绍的比较形象 Android总结篇系列:Activity启动模式(lauchMode)

上面遗留问题

上面我们有提到过一个 “Activity所需要的任务栈”的概念

关于singleTask模式其实有一个 “Activity所需的任务栈”的概念;什么是Activity所需要的任务栈呢?这就牵扯到一个参数“TaskAffinity”,可以翻译为任务相关性。这个参数标识了一个Activity所需要的任务栈的名字,默认情况下,所有Activity所需要的任务栈的名字为应用的包名。当然我们可以为每个Activity都单独指定TaskAffinity属性,这个属性值必须不能和包名相同,否则就相对于没有指定。TaskAffinity属性注和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有任何意义。

当TaskAffinity和singleTask启动模式配对使用的时候,它是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。

当TaskAffinity和allowTaskReparenting结合的时候,这种情况比较复杂,会产生特殊的效果。当一个应用A启动了应用B的某个Activity后,如果这个Activity的allowTaskReparenting属性为true的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中。举个例子:比如现在有2个应用A和B,A启动了B的一个Activity C,然后按Home键回到桌面,然后在单击B的桌面图标,这个时候并不是启动了B的主Activity,而是重新显示了已经被应用A启动的Activity C,或者说,C从A的任务栈转移到了B的任务栈中。可以这么理解,由于A启动了C,这个时候C只能运行在A的任务栈中,但是C属于B应用,正常情况下,它的TaskAffinity值肯定不可能和A的任务栈相同(因为包名不同)。所以,当B被启动后,B会创建自己的任务栈,这个时候系统发现原来C原本想要的任务栈已经被创建了,所以就把C从A的任务栈中转移过来了

想了解关于TaskAffinity属性的可以看下这篇博客 Android中Activity四种启动模式和taskAffinity属性详解

下面就是一一验证上面例子的时候了

在验证之前我们还需要做一件事,那就是要知
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值