Activity生命周期 | 进阶之路

530 阅读8分钟

前言:

Activity作为四大组件之一,中文翻译直接翻译为“活动”,是日常应用中与用户交互的接口,它提供了供用户操作的窗口,正常情况下,除了Window、Dialog和Toast,我们能见到的界面只有Activity。

学习清单

  • Activity的生命周期
  • Activity的启动模式
  • IntentFilter的匹配规则

一、Activity的生命周期

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

1.1.2 Activity常用的生命周期

  • onCreate:表示Activity正在被创建,生命周期的第一个方法。
  • onRestart:表示Activity正在重新启动。
  • onStart:表示Activity正在被启动。
  • onResume:表示Activity是可见的,出现在前台并且开始活动。
  • onPause:表示Activity正在停止。
  • onStop:表示Activity即将停止。
  • onDestory:表示Activity即将被销毁。

​ 图 1-1

问:一个Activity的生命周期中可能会出现哪几种情况?

(1)Activity第一次启动时,回调有:onCreate -> onStart -> onResume

(2)用户打开新的Activity或者切换到桌面时:onPause -> onStop。若Activity采用了透明主题,则Activity不会回调onStop

(3)用户再回到原Activity时:onRestart -> onStart -> onResume

(4)用户按Back键回退时:onPause -> onStop -> onDestroy

(5)当Activity被系统回收再打开时,生命周期与(1)一样。

(9)onCreateonDestroy分别标识着Activity的创建和销毁,在整个生命周期中只有一次调用。

问:onStartonStoponResumeonPause有什么区别?

  • onStartonStop分别标识着Activity的开始和停止,前者Activity可见,后者Activity不可见。
  • onResumeonPause分别标识着Activity的继续和暂停。前者Activity在前台,后者Activity在后台。

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

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

​ 图1-2

举个例子:当前Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity就会被销毁并重新创建,其生命周期如图1-2所示。

分析:当系统配置发生更改后,Activity会被销毁,其onPauseonStoponDestroy都会被调用,由于Activity是在异常情况下终止的,系统会调用onSaveInstanceState来保存当前Activity的状态(这个方法只会出现在Activity异常终止的情况下,正常情况下不会调用这个方法)。

Activity被重新创建后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象作为参数传递给onRestoreInstanceStateonCreate方法。

因此,可以通过onRestoreInstanceStateonCreate方法来判断Activity是否被重建了,如果被重建了,我们就可以取出之前保存的数据并恢复,从时序上来说,onRestoreInstanceState的调用时机在onStart之后。

1.1.2资源内存不足导致优先级低的Activity被杀死

Activity优先级从高到低可以分为以下三种:

  • 前台Activity ——正在和用户交互的Activity,优先级最高。

  • 可见但并非前台Activity——比如Activity中弹出一个对话框,导致Activity可见,但是位于后台无法和用户交互。

  • 后台Activity——已经被暂停的Activity,比如执行了onStop,优先级最低。

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

1.2 Activity的启动模式

1.2.1 ActivityLaunchMode

任务栈:一种“先进后出”的栈结构,存放Activity实例。

问:Activity有哪几种启动模式?

(1)standard:标准模式,也是系统的默认模式,每次启动Activity都会重新创建一个新的实例,不管这个实例是否已经存在。

(2)singleTop:栈顶复用模式,如果新的Activity位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会回调。

(3)singleTask:栈内复用模式。一种单实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和singleTop一样,系统也会回调onNewIntent

  • 比如任务栈S1中有ABC,这个时候Activity D以singleTask模式请求启动,其所需的任务栈为S2,由于S2和D的实例都不存在,系统会先创建任务栈S2,然后再创建D的实例并将其入栈到S2。
  • 假设D所需的任务栈为S1,其他情况与上述一样,由于S1存在,所以系统会直接创建D 的实例并将其入栈到S1。
  • 如果D所需的任务栈为S1,并且当前任务栈S1的情况为ADBC,此时D不会被创建,系统会把D切换到栈顶并调用其onNewIntent方法,singleTask默认具有clearTop效果,导致栈内所有在D上面的Activity全部出栈,最终S1中的情况为AD。

(4)singleInstance:单实例模式,一种加强的singleTask模式,除了singTask模式的所有特性外,还加强了一点,那就是具有此种模式的Activity只能单独地位于一个任务栈中。

举个启动模式的小例子:

假设目前有两个任务栈,前台任务栈情况为AB,而后台任务栈情况为CD,假设CD的启动模式均为singleTask。现在请求启动D,那么整个后台任务都会切换到前台,这个时候按下back键的后退列表为ABCD,如图1-3。如果请求启动D而不是启动C,后退列表为ABC,如图1-4。

​ 图1-3

​ 图1-4

问:在singleTask启动模式中,多次提到某个Activity所需的任务栈,什么是Activity所需的任务栈?

参数TaskAffinity标识了一个Activity所需要的的任务栈的名字,默认情况下,此参数为应用的包名,可以自己指定,TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。

任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity处于暂停状态。

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

TaskAffinityallowTaskReparenting结合的时候,当一个应用A启动应用B 的某个Activity后,这个ActivityallowTaskReparenting属性为true的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中。

1.2.2 Activity的Flags

Activity常用的标记位:

  • FLAG_ACTIVITY_NEW_TASK :为Activity指定“singleTask”启动模式。

  • FLAG_ACTIVITY_SINGLE_TOP:为Activity指定“singleTop”启动模式。

  • FLAG_ACTIVITY_CLEAR_TOP:具有此标记位的Activity,当它启动时,在同一任务栈所有位于它上面的Activity都要出栈,此标记一般会与singleTask一起出现。

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有此标记的Activity不会出现在历史Activity的列表中,等同 android:excludeFromRecents = "true"

1.3 IntentFilter的匹配规则

启动Activity分为两种,显示调用和隐式调用。显示调用需要明确指定被启动对象的组件信息,包括包名和类名,而隐式调用则不需要明确指定组件信息。

隐式调用:Intent 能够匹配目标组件中的actioncategorydata 这三个过滤信息,只有一个Intent能同时匹配这三种过滤信息才算完全匹配。

  • 只有一个intent同时匹配 actioncategorydata 才算完全匹配,只有 完全匹配 才能启动activity

  • 一个 activity 可以 有多个 intent-filter ,一个 intent 只要成功匹配任意一组intent-filter 就可以启动activity

A. action的匹配规则

  • action的匹配要求Intent中的action 存在且必须和过滤规则中的其中action 相同

  • action 是区分大小写的。

B. category的匹配规则

  • ntent中的 category 只要有一个和 匹配规则中的category 相同就可以匹配。

  • intent 不设置 category ,也可以和其匹配,因为系统在调用 startActivity 或者 startActivity ForResult的时候会自动添加 android.intent.category.DEFAULT 这个category

C. data的匹配规则

  • 类似于action

  • 如果过滤规则中有data,那么intent中也必须定义可匹配的data

  • data由 两部分组成:mimeTypeUrl

    说明:Url默认值为 contentfile。如果Intent指定完整的data,必须调用setDataAndType方法。

1.4 问题扩展

1.onStartonResumeonPauseonStop 从描述上差不多,对我们来说有什么实质上的不同?

onStartonResume是从Activity是否可见的角度来回调的,onPauseonStop是从Activity是否在前台来回调的。

2.假设当前Activity为A,如果这时用户打开一个新ActivityB,那么B的onResume和A 的onPause哪个先执行?

A的onPause先执行。

3.当系统配置发生变化时,Activity会被重新创建,有什么办法能够不重新创建?

可以给Activity指定configChanges属性。例如不想让Activity旋转时重新创建,可以给configChanges属性添加orientation这个值。 android:configChanges="orientation"

本文参考: