Android开发艺术探索 | Activity的生命周期和启动模式

在之前的学习中,每天都在写Activity,却又不知道Activity到底是啥, 只知道一个页面配上一个Activity,放个Intent就能让它跑到别的Activity里去. 现在在通过这本书重新认识一下Activity.

本博文借鉴了 厘米姑娘
旨在培养自己养成好的写作习惯,已与作者联系.

学习清单:

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

一.Activity生命周期全解析

1.Q: 典型情况下的生命周期分析

A:
a.onCreate():

  • 状态: Activity 正在创建
  • 任务: 做一下初始化工作,如setContentView界面资源、初始化数据
  • 注意: 此方法的传参Bundle为该Activity上次被异常情况销毁时保存的状态信息

b.onStart():

  • 状态: Activity 正在启动, 此时Activity 可见但不在前台, 无法和用户交互

c.onResume():

  • 状态: Activity 获得焦点, 此时Activity 可见且在前台并开始活动

d.onPause():

  • 状态: Activity 正在停止
  • 任务: 做一些存储数据、停止动画等工作
  • 注意: 动作不能太耗时, 会影响到新Activity的显示

e.onStop():

  • 状态: Activity 即将停止
  • 任务: 做一些稍微重量级的回收工作
  • 注意: 不能太耗时

f.onDestroy():

  • 状态: Activity 即将销毁
  • 任务: 回收工作最终资源释放

g.onRestart():

  • 状态: Activity 重新启动, Activity由后台切换到前台,由不可见到可见

onStart() 和onResume()、onPause() 和onStop()的区别: onStart() 和onStop() 是从Activity是否可见来回调的, 而 onResume() 和onPause() 是从Activity是否位于前台来回调的. 在实际使用中没有其他明显区别

推荐阅读: Activity生命周期通俗易懂的理解

2.Activity生命周期的切换过程

第一次启动Activity:

  • onCreate -> onStart -> onResume

打开新的Activity:

  • 旧Activity: onPause -> 新Activity: onCreate -> onStart -> onResume -> 旧Activity: onStop()

注意: 如果新Activity采用透明主题, 则不会回调onStop

回到旧的Activity:

  • 新Activity: onPause -> 旧Activity: onRestart -> onStart -> onResume -> 新Activity: onStop -> onDestroy

Activity1上弹出对话框Activity2:

  • Activity1: onPause -> Activity2: onCreate -> onStart -> onResume

关闭屏幕/按Home键:

  • Activity2: onPause -> onStop -> Activity1: onStop

点亮屏幕/回到前台:

  • Activity2: onRestart -> onStart -> Activity1: onRestart -> onStart -> Activity2: onResume

关闭对话框Activity2:

  • Activity2: onPause -> Activity1: onResume -> Activity2: onStop -> onDestroy

销毁Activity1:

  • Activity1: onPause -> onStop -> onDestroy

3.Q:生命周期的各阶段:

A:
a.完整生命周期
Activity在onCreate()和onDestroy()之间所经历的
在onCreate()中完成各初始化操作, 在onDestroy()中释放资源

b.可见生命周期
Activity在onStart()和onStop()之间所经历的
活动对于用户是可见的, 但仍无法与用户进行交互

c.前台生命周期
Activity在onResume()和onPause()之间经历的
此时活动不仅可见, 也可与用户进行交互

4.onSaveInstanceState 和 onRestoreInstanceState

a.出现时机: 异常 情况下Activity需要 重建, 而非用户主动销毁

b.系统异常终止时,调用onSavaInstanceState来保存状态。该方法调用在onStop之前,但和onPause没有时序关系。

onSaveInstanceStateonPause的区别:前者适用于对临时性状态的保存,而后者适用于对数据的持久化保存。

c.Activity被重新创建时,调用onRestoreInstanceState(该方法在onStart之后),并将onSavaInstanceState保存的Bundle对象作为参数传到onRestoreInstanceState与onCreate方法。

可通过onRestoreInstanceState(Bundle savedInstanceState)和onCreate(Bundle savedInstanceState)来判断Activity是否被重建,并取出数据进行恢复。但需要注意的是,在onCreate取出数据时一定要先判断savedInstanceState是否为空。另外,谷歌更推荐使用onRestoreInstanceState进行数据恢复。

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

a.资源相关的系统配置文件改变, 导致Activity被杀死并重新创建
例如在横竖屏切换时, Activity会先通过onSavedInstanceState记录下当前的数据, 再销毁Activity. 当Activity重新创建(onCreate)时, 系统又会调用onRestoreInstanceState取出之前保存的数据.

生命周期: onPause -> onSaveInstanceState -> onStop -> onDestroy -> Activity: onCreate -> onRestoreInstanceState

b.资源内存不足, 导致低优先级的Activity被杀死
①优先级(从高到低):

  • 前台Activity(用户可交互) -> 可见但非前台Activity(如弹出对话框后的Activity) -> 后台Activity(用户按下Home键或切换到其他应用)

②当系统内存不足时, 就会按照优先级去杀死目标Activity所在的进程

③一个进程若没有四大组件独自运行在后台, 则很容易被杀死

当系统配置发生改变时, 如果想让Activity不重新创建, 可以给Activity指定configChanges属性. 比如在屏幕旋转不想重新创建时添加:android:configChanges="orientation"


二.Activity的启动模式

1.Activity的LaunchMode

默认情况下, 如果我们重复创建多个Activity, 它们都会被放入任务栈中, 当我们按下back键, 就会从栈顶弹出一个Activity. 为了避免这种情况发生, Android提供了四种启动模式来修改系统的默认启动行为

a.standard: 标准模式 | 默认模式

  • 效果: 每次启动一个Activity都会重新创建一个新实例, 无论是否已经存在
  • 注意: 不能使用ApplicationContext去启动standard模式的Activity, standard模式下Activity会默认进入启动它的Activity所属的任务栈中, 而Context没有任务栈

解决方法: 为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位

b.singleTop: 栈顶复用模式

  • 效果: 位于栈顶的Activity不会被重复创建, 同时会调用onNewIntent(intent)方法
  • 注意: 如果Activity已经在任务栈中并且不是位于栈顶, 那么该Activity仍然会被创建

c.singleTask: 栈内复用模式

  • 效果: 在任务栈中的Activity不会被重新创建, 同时会调用onNewIntent(intent)方法. 如果不存在所需的任务栈, 则会建一个新的任务栈存入, 如果存在所需的任务栈, 则会将该Activity调到栈顶并调用onNewIntent(intent)方法

所需: TaskAffinity参数标识了一个Activity所需的任务栈的名字, 默认情况下为当前应用的包名

  • 注意: 由于singleTask默认具有clearTop效果, 会导致栈内的目标Activity上所有的Activity全部出栈.

例如: 例如有一个任务栈的情况为ABCD, 栈底是A, 栈顶是D, 当我想要创建一个Activity B时, 会将C和D弹出, 此时任务栈只剩下AB

d.singleInstance: 单实例模式

  • 效果: 这是一个加强版的singleTask, 具有此模式的Activity只能单独位于一个任务栈中

推荐阅读: 彻底弄懂Activity的启动模式和任务栈、对应的应用情景


2.Q:如何为Activity指定启动模式

A:
通过AndroidMenifest:


通过Intent:

Intent intent = new Intent();
intent.setClass(MainActivity.this, TestActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

注意:

  • 在优先级上, Intent方式要高于AndroidMenifest, 同时存在的话以Intent方式为主
  • AndroidMenifest无法设定FLAG_ACTIVITY_CLEAR_TOP标识, 而Intent无法设定singleInstance模式

3.Activity的Flags

FLAG_ACTIVITY_NEW_TASK: singleTask模式

FLAG_ACTIVITY_SINGLE_TOP: singleTop模式

FLAG_ACTIVITY_CLEAR_TOP: 启动时清空该Activity上的所有Activity, singleTask默认具有此标记位效果

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS: 具有该标志位的Activity不会出
现在历史Activity的列表中


三.IntentFilter的匹配规则

启动Activity有两种方式, 一种是显式启动, 另一种是隐式启动.

  • 显式启动: 明确指定被启动对象的组件信息, Intent intent = new Intent(MainActivity.this, TargetActivity.class)
  • 隐式启动: 需要Intent匹配IntentFilter中的过滤信息

原则:
①一个intent只有同时匹配某个Activity的intent-filter中的action、category、data才算完全匹配,才能启动该Activity。
② 一个Activity可以有多个 intent-filter,一个 intent只要成功匹配任意一组 intent-filter,就可以启动该Activity。

a.action 的匹配规则:

  • Intent中必须要有一个action
  • 只要Intent中的action能匹配上过滤规则的其中一个即可
  • 过滤规则中的action可以有多个

b.category 的匹配规则:

  • Intent中可以没有category, 系统给所有Activity默认加上了< category android:name="android.intent.category.DEAFAULT" />
  • Intent中如果有category, 那么Intent中的category要和过滤规则中的所有category相同

c.data的匹配规则:

  • 如果过滤规则中定义了data, 则Intent中也要定义匹配的data.
  • 只要Intent中的data能匹配上过滤规则的其中一个即可
  • data主要由mimeType(媒体类型)和URI组成。在匹配时通过intent.setDataAndType(Uri data, String type)方法对date进行设置。

采用隐式方式启动Activity时,可以用PackageManager的resolveActivity方法或者Intent的resolveActivity方法判断是否有Activity匹配该隐式Intent。


对Activity的探索就暂告一段落啦, 但是在以后的开发过程中, 还要时不时的回忆一下这些内容, 只有用了才是自己的, 多实践别光看.

你可能感兴趣的:(Android开发艺术探索 | Activity的生命周期和启动模式)