您的位置:首页 > 移动开发 > Android开发

[基础] 1. Activity的生命周期和启动模式

2018-03-15 17:08 477 查看

生命周期

先看网上这张经典图



AMS -> ApplicationThread -> 通过ActivityThread H handler切到主线程,handleLaunchActivity会完成OnCreate,onStart,onResume的调用

每个生命周期的意义

先来了解下每个生命周期的意义

名字意义Activity状态备注
onCreateActivity创建。适合像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对象还在内存中,没有被销毁,主要做一些资源的回收工作
onDestroyActivity被销毁不可见适合做资源释放和回收工作
onRestart重新开始可见Home键到桌面后又切回来或者从其他Activity切回来会触发,一般不做什么操作

相邻方法的区别

除了onRestart,生命周期的方法都是两两对应,除了OnCreate和onDestroy其他都可能被调用多次。

我们来了解下相邻的方法之间的区别



onCreate和onStart

名称Activity状态执行次数备注
onCreate不可见Activity创建时执行一次官方推荐资源的初始化,setContentView放在这里
onStart可见Activity创建,切换/back Home再回来过程中被多次调用Bundle数据的恢复更适合这里;资源的初始化,setContentView亦可以,只是习惯问题;
onStart方法和onResume

名称Activity状态备注
onStart可见,但在后台初始化,Bundle数据的恢复
onResume前台,可交互官方建议,可以做开启动画和UI交互的操作
onPause方法和onStop

名称Activity状态备注
onPause前台,可见程序状态的保存、交互和动画的关闭以及一些数据的保存等不太耗时操作最好在onPause中进行
onStop不可见在系统内存不足的时候可能不会执行onStop方法
只有当一个Activity执行完了onPause方法后另一个Activity才会启动。android中指定如果onPause在500ms即0.5秒内没有执行完毕的话就会强制关闭Activity。

正常情况下,紧接着onStop就会被调用。特殊情况nResume会被调用,比如快速地回到当前Activity。

onStop方法和onDestroy

名称备注
onStopActivity还没有被销毁,对象还在内存中,可以通过切换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
1. standard模式启动Activity默认会进入启动它的Activity所属的任务栈。因此只能用Activity类型的Context启动这类Activity,如果使用Application、Service 等启动会报错。除非给Activity指定FLAG_ACTIVITY_NEW_TASK标记位

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android