在之前的学习中,每天都在写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没有时序关系。
onSaveInstanceState与onPause的区别:前者适用于对临时性状态的保存,而后者适用于对数据的持久化保存。
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的探索就暂告一段落啦, 但是在以后的开发过程中, 还要时不时的回忆一下这些内容, 只有用了才是自己的, 多实践别光看.