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:

<activity
    android:name="com.ryg.chapter_1.MainActivity"
    android:label="@string/app_name"
    android:configChanges="screenLayout"
    android:launchMode="singleTask" />

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容