[基础] 1. Activity的生命周期和启动模式
2018-03-15 17:08
477 查看
生命周期
先看网上这张经典图AMS -> ApplicationThread -> 通过ActivityThread H handler切到主线程,handleLaunchActivity会完成OnCreate,onStart,onResume的调用
每个生命周期的意义
先来了解下每个生命周期的意义名字 | 意义 | Activity状态 | 备注 |
---|---|---|---|
onCreate | Activity创建。适合像setContentView,控件和变量等初始化 | 后台不可见 | ActivityThread创建Activity实例之后回调OnCreate |
onStart | 启动 | 可见但在后台 | 适合Bundle数据的恢复 |
onResume | 继续、重新开始 | 前台,可见 | onResume会调用makeVisibale让DecorView visible; 官方建议,可以做开启动画和用户交互的操作 |
onPause | 暂停 | 前台,可见 | 适合程序状态的保存、交互和动画的关闭、以及一些数据的保存等不太耗时的操作;Activity跳转或正常退出都会执行。只有当一个Activity执行完了onPause方法后另一个Activity才会启动。android中指定如果onPause在500ms即0.5秒内没有执行完毕的话就会强制关闭Activity。正常情况下,紧接着onStop就会被调用。特殊情况nResume会被调用,比如快速地回到当前Activity |
onStop | 停止 | 不可见 | Activity对象还在内存中,没有被销毁,主要做一些资源的回收工作 |
onDestroy | Activity被销毁 | 不可见 | 适合做资源释放和回收工作 |
onRestart | 重新开始 | 可见 | Home键到桌面后又切回来或者从其他Activity切回来会触发,一般不做什么操作 |
相邻方法的区别
除了onRestart,生命周期的方法都是两两对应,除了OnCreate和onDestroy其他都可能被调用多次。我们来了解下相邻的方法之间的区别
onCreate和onStart
名称 | Activity状态 | 执行次数 | 备注 |
---|---|---|---|
onCreate | 不可见 | Activity创建时执行一次 | 官方推荐资源的初始化,setContentView放在这里 |
onStart | 可见 | Activity创建,切换/back Home再回来过程中被多次调用 | Bundle数据的恢复更适合这里;资源的初始化,setContentView亦可以,只是习惯问题; |
名称 | Activity状态 | 备注 |
---|---|---|
onStart | 可见,但在后台 | 初始化,Bundle数据的恢复 |
onResume | 前台,可交互 | 官方建议,可以做开启动画和UI交互的操作 |
名称 | Activity状态 | 备注 |
---|---|---|
onPause | 前台,可见 | 程序状态的保存、交互和动画的关闭以及一些数据的保存等不太耗时操作最好在onPause中进行 |
onStop | 不可见 | 在系统内存不足的时候可能不会执行onStop方法 |
正常情况下,紧接着onStop就会被调用。特殊情况nResume会被调用,比如快速地回到当前Activity。
onStop方法和onDestroy
名称 | 备注 |
---|---|
onStop | Activity还没有被销毁,对象还在内存中,可以通过切换Activity再次回到该Activity |
onDestroy | 可见 |
典型的生命周期
典型情况下的生命周期,是指在所有用户参与的情况下,Activity所经过的生命周期的改变Activity (A) 第一次启动:onCreate()->onStart()->onResume()
A 切到到桌面:onPause()->onStop();如果Activity采用了透明主题,不会回调onStop()
A 切换到 Activity (B):(A)onPause->(B)onCreate->(B)onStart->(B)onResume->(A)onStop ;如果Activity采用了透明主题,不会回调onStop()
应为源码中新的Activity启动之前,栈顶的Activity需要先onPause
桌面或B切回到A:onRestart()->onStart()->onResume()
back键退出:onPause()->onStop()->onDestory()
异常情况下的生命周期
异常情况下Activity被销毁,系统会调用onSaveInstanceState来保存当前的Activity状态。当Activity被重新创建后,系统会调用onRestoreInstanceState系统会调用onSaveInstanceState的时机是在onStop之前,和onPause没有既定的时序关系。
Activity会委托Window去保存,一般是DecorView这顶层容器再一一通知它的子元素来保存数据。典型的委托思想
仅在Activity被异常终止的情况下调用。正常情况下系统是不会回调
当Activity被重新创建后,系统会调用onRestoreInstanceState,并且把onSaveInstanceState方保存的bundle对象传递给onRestoreInstanceState和onCreate方法
在异常情况下,系统会默认保存当前Activity的视图结构,并且在Activity重启后为我们恢复这些数据
比如文本框中用于输入的数据、ListView滚动的位置等。详细的恢复数据可以查看 每个View的onSaveInstanceState和onRestoreInstanceState
异常情况包括:
资源相关的系统配置发生改变导致Activity被杀死并重新创建
比如转屏,系统语言等。如果我们Activity不做特殊处理,Activity会被销毁
资源内存不足导致低优先级的Activity被杀死。
优先级从高到低依次为:前台Activity、可见但并非前台的Activity和后台的Activity
如果进程中没有四大组件在执行,进程将很快被系统杀死。因此后台任务建议放入Service中处理
系统配置发生变化后,我们可以通过设置android:configChanges来避免Activity的重建,而是调用Activity的onConfigurationChanged方法。常用的几个选项:
local:设备的本地位置发生了变化,一般是切换了系统语言
keyboardHidden:键盘的可访问性发生了变化,比如用户调出了键盘;
orientation:屏幕方向发生了变化,比如旋转了手机屏幕。
另外在来看看onSaveInstanceState方法和onRestoreInstanceState的执行时机
O上onSaveInstanceState是在onStop方法中调用
onRestoreInstanceState是在onStart之后,onResume之前调用
生命周期总结:
onCreate :适合setContentView,控件和变量等初始化
onStart :适合Bundle数据的恢复
4000
onResume:可以做开启动画和交互的操作|
onPause:适合程序状态的保存、交互和动画的关闭、以及一些数据的保存等不太耗时的操作
onStop:一些资源的回收工作
onDestroy:适合做资源释放和回收工作
onRestart:一般不做什么操作
异常情况下Activity被销毁,系统会调用onSaveInstanceState来保存当前的Activity状态。当Activity被重新创建后,系统会调用onRestoreInstanceState
onConfigurationChanged可以避免Activity重建
Activity启动模式
四种启动模式对比名称 | 特性 | 备注 |
---|---|---|
standard | 默认标准模式,每次都新建实例 | standard模式启动Activity默认会进入启动它的Activity所属的任务栈 |
singleTop | 栈顶复用,只要Activity在栈顶就不新建 | 栈顶Activity复用时onNewIntent会被回调 |
singleTask | 栈内复用,只要栈内存在Activity就不新建,调到栈顶 | 复用时onNewIntent会被回调 |
singleInstance | 单例模式,单独位于一个任务栈中 | 加强版的singleTask |
2. singleTask Activity (A)启动
先检查所需任务栈是否存在,不存在就创建任务栈,创建A放入栈顶;
如果任务栈存在,但A不在栈顶,把A调到栈顶 (onNewIntent会被调用)
如果任务栈存在,但A不存在,创建A放入栈顶
3. singleTask默认具有clearTop的效果,会将上面的Activity全部出栈
例如前台任务栈S1的情况是AB (B是栈顶),后台任务栈S2的情况是DC(C是栈顶,DC都是SingleTask)
如果此时请求启动D,D切换到栈顶,并调用其onNewIntent。整个后台任务栈都会被切换到前台。
整个后退列表ABD
4. singleInstance Activity 启动后,系统会为它创建一个新的任务栈。由于栈内复用,后续的请求都不会新建,除非任务栈被销毁
有两个地方可以设置Activity的启动模式:AndroidMenifest 和代码intent.addFlags()
代码intent.addFlags()优先级
AndroidMenifest无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识
代码intent.addFlags()无法指定singleInstance模式。
注意事项:
1. 当栈中没有任何Activity的时候,系统就会回收这个任务栈
2. 任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity位于暂停状态,用户可以通过切换将后台任务栈再次调到前台
3. Activity不重建,复用时调到栈顶会调用onNewIntent
4. TaskAffinity参数,标识了Activity所需要的任务栈的的名字;默认是应用的包名
TaskAffinity主要和SingleTask启动模式或者allowTaskReparenting属性配对使用
5. TaskAffinity和singleTask搭配,singleTask Activity 会运行在名字和TaskAffinity相同的任务栈中
6. TaskAffinity和allowTaskReparenting搭配,情况比较复杂
两个不同的应用A,B。当应用 A启动了应用B 的Activity C,如果B的allowTaskReparenting = true 会有下面的现象:
点击home到主界面,然后点击启动应用 B,此时并不是启动了B的主Activity,而是重新显示Activity C
原因是:A启动了C,C只能运行在A的任务栈中,但是C属于B应用。正常情况下C的TaskAffinity肯定不可能跟A任务栈相同。所有当B启动后,B会创建自己的任务栈,系统发现C想要的任务栈已经被创建了,所以就把C从A的任务栈中一过来。
Activity的Flags
Activity的Flags有很多,常用的有设定Android启动模式:FLAG_ACTIVITY_NEW_TASK、 FLAG_ACTIVITY_SINGLE_TOP、
影响Activity运行状态:FLAG_ACTIVITY_CLEAR_TOP、FLAG_ACITIVTY_EXCLUDE_FROM_RECENTS
FLAG_ACITIVTY_EXCLUDE_FROM_RECENTS:具有这个标记的Activity不会出现在历史Activity列表中。等同于属性设置android:excludeFromRecents=”true”
singleTop Activity默认有FLAG_ACTIVITY_CLEAR_TOP,启动时,前方所以Activity全部出栈
IntentFilter的匹配规则
启动Activity分为显示调用和隐式调用。显示调用需要明确的指定被启动对象的组件信息(包名和类名);
隐式调用不需要指定明确的组件信息,需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息
startActivity发送intent,目标Activity通过IntentFilter来匹配
发送端启动示例 (Intent)
final static String ACTION_TEST = "com.test.action"; final static String CATEGORY_TEST = "com.test.category"; Intent intent = new Intent(ACTION_TEST); intent.addCategory(CATEGORY_TEST) intent.setDataAndType(Uri.parse("file://abc"), "text/plain"); startActivity(intent);
接收端的示例 (过滤列表)
<intent-filter> <action android:name="com.test.action" /> <action android:name="com.test.action_1" /> <category android:name="com.test.category" /> <data android:mimeType="text/plain" /> </intent-filter>
IntentFilter中的过滤信息由action、category、data
需要同时匹配过滤信息中的actiion、category、data信息,否则匹配失败。
所有的action、category、data分别构成不同类别,同一类别的信息共同约束当前类别的匹配过程
过滤列表中的action、category、data可以有多个
Activity可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity
action、category、data的匹配规则
action匹配规则
action是一个字符串
Intent 中必须存在action,这点和category不同
Intent中的action必须和过滤列表中的某一个action完全匹配
action的字符串严格区分大小写;
过滤列表中可以同时有多个action,但是Intent只需与其中之一相同即可匹配成功;
category匹配规则
category是一个字符串
Intent可以不设category,startActivity默认给Intent加上“android.intent.category.DEFAULT”,因此过滤列表中必须添加“android.intent.category.DEFAULT” 才能接收隐式intent
Intent中可以同时设置多个category,但是每个category都必须能够和过滤列表的某个category匹配成功
data匹配规则:和action类似
Intent中必须有data数据
Intent中的data必须和过滤列表中的某一个data完全匹配
过滤列表中可以有多个data存在,但是Intent中的data只需匹配其中的任意一个data即可
过滤列表中可以没有指定URI,但是系统会赋予其默认值:content和file,这一点在Intent中需要注意
为Intent设定data的时候必须要调用setDataAndType方法,而不能先setData再setType,因为这两个方法是互斥的,都会清除对方的值,这个有兴趣可以参见源码
在匹配规则中,data的scheme,host,port,path等属性可以写在同一个< />中,也可以分开单独写,其功效是一样的
data包含两部分:mimeType和URI.
mimeType表示image/ipeg,video/*等媒体类型
URI信息量相对大一点,其结构一般为:
<scheme>://<host>:<port>/[<path>|<pathPrefix|<pathPattern>>]
各个节点数据的含义
<data android:scheme="string" android:host="string" android:port="string" android:path="string" android:pathPattern="string" android:pathPrefix="string" android:mimeType="string" />
scheme:整个URI的模式。如常见的http, file, content等。如果URI中没有指定的scheme,那么整个uri无效
host:URI的域名。比如www.baidu.com。一旦没有host那么整个URI也毫无意义
port:端口号,比如80。只有在URI中指定了scheme和host之后端口号才是有意义的
path,pathPattern,pathPrefix包含路径信息
path表示完整的路径
pathPattern在此基础上可以包含通配符
pathPrefix表示路径的前缀信息
其他
为了避免不匹配异常,建议PackageManager或者Intent的resolveActivity做预判断android.intent.action.MAIN 和 android.intent.category.LAUNCHER
这两个成双成对出现,决定应用程序在luncher中的显示方式,表明这是一个程序的入口并且会出现在系统的应用列表
// 决定应用程序最先启动的Activity <action android:name="android.intent.action.MAIN"/> // 决定应用程序是否显示在程序列表里 <category android:name="android.intent.category.LAUNCHER"/>
如果只有一个activity的应用程序只声明了android.intent.action.MAIN ,没有声明 android.intent.category.LAUNCHER运行会报错”No Launcher activity found”
如果多个activity都声明了android.intent.action.MAIN与android.intent.category.LAUNCHER,将会有多个图标显示在桌面上
Reference
《Android 开发艺术探索》读书笔记 http://blog.csdn.net/a296777513/article/details/54729355相关文章推荐
- 回顾基础知识--第一章:Activity的生命周期和启动模式
- 【幻化万千戏红尘】qianfeng-Android-Day05-Activity生命周期,Actitity的启动模式基础学习:
- Activity生命周期与启动模式基础知识备忘录
- Android基础:Activity回顾(生命周期、启动模式)
- android基础重点总结(分层架构,五中布局,activity的生命周期和四种启动模式)
- 基础总结篇:Activity生命周期 四种启动模式 以及TASK
- Android核心基础-8.Android四大组件之Activity-3.生命周期、横竖屏切换、启动模式、进程管理
- Android基础相关面试问题-activity面试问题(生命周期,任务栈,启动模式,跳转协议)
- 【Android基础】Activity的启动模式(android:launchMode)
- activity的生命周期及启动的四种模式,栈管理
- Activity生命周期与启动模式图文解说
- Activity的生命周期和启动模式
- Activity的生命周期和启动模式(二)
- 【读书笔记】【Android 开发艺术探索】第1章 Activity 的生命周期和启动模式
- Activity的生命周期和启动模式
- 第一章 Activity的生命周期和启动模式
- Activity的生命周期和启动模式
- 读书笔记—Activity的生命周期和启动模式
- 笔记一 Android开发艺术探索之Activity的生命周期和启动模式
- 第一章、Activity 的生命周期和启动模式