Android开发艺术探究(一):Activity的生命周期和启动模式

1. Activity生命周期的全面解析

1.1. 典型情况的生命周期

onCreate->onStart->onResume->onPause->onStop->onDestroy

 

1.1.1. Activity第一次启动时:onCreate--onStart--onResume

1.1.2. 打开的Activity切换到桌面或者打开新的Activity时:当前Activity执行onPause--onStop,特殊情况,当打开一个透明主题的Activity时,只执行onPause

1.1.3. 当用户再次回到原Activity时:onRestart--onStart--onResume

1.1.4. 当用户按back键返回时:onPause--onStop--onDestroy

1.1.5. Activity被系统回收时再次打开:onCreate--onStart--onResume

1.1.6. AActivity中打开BActivity时:先执行AActivityonPause,然后执行BActivityonCreateonStartonResume,最后执行AActivityonStop

注:我们尽量在onStop中做操作,而不要在onPause中做,使新的Activity能够尽快显示

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

1.2.1. 情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建:比如横竖屏切换时

此种情况下,Activity会调用onSaveInstanceState方法保存数据,调用时机为onStop之前,它和onPause没有先后关系,重新创建时会调用onRestoreInstanceState方法恢复数据,调用时机为onStart方法之后。我们发现在onCreate方法中也有saveInstanceState参数,我们也可以使用它做恢复数据操作,它与onRestoreInstanceState的区别在于:使用onCreate恢复数据时,需要对saveInstanceState进行判null操作,因为在创建新的Activity时,它是null的,而使用onRestoreInstanceState方法则不需要。

1.2.1.1. 竖屏切横屏

执行onPauseonSaveInstanceState--onStop--onDestroy--onCreate--onStart--onRestoreInstanceStateonResume

1.2.1.2. 横屏切竖屏

执行onPauseonSaveInstanceState--onStop--onDestroy--onCreate--onStart--onRestoreInstanceStateonResume

--onPauseonSaveInstanceState--onStop--onDestroy--onCreate--onStart--onRestoreInstanceStateonResume

 

1.2.1.3. 修改AndroidManifest.xml,把该Activity添加 Android:configChanges="orientation",竖屏切横屏

执行onPauseonSaveInstanceState--onStop--onDestroy--onCreate--onStart--onRestoreInstanceStateonResume

1.2.1.4. 修改AndroidManifest.xml,把该Activity添加 Android:configChanges="orientation",横屏切竖屏

执行onPauseonSaveInstanceState--onStop--onDestroy--onCreate--onStart--onRestoreInstanceStateonResume

--onConfigurationChanged

1.2.1.5. 修改AndroidManifest.xml,把该Activity添加 Android:configChanges="orientation|keyboardHidden",竖屏切横屏

执行onConfigurationChanged

1.2.1.6. 修改AndroidManifest.xml,把该Activity添加 Android:configChanges="orientation|keyboardHidden",横屏切竖屏

执行onConfigurationChangedonConfigurationChanged

注:自从Android 3.2API 13),在设置Activityandroid:configChanges="orientation|keyboardHidden"后,还是一样会重新调用各个生命周期的。因为screen size也开始跟着设备的横竖切换而改变。所以,在AndroidManifest.xml里设置的MiniSdkVersionTargetSdkVersion属性大于等于13的情况下,如果你想阻止程序在运行时重新加载Activity,除了设置"orientation",你还必须设置"ScreenSize"
解决方法:
AndroidManifest.xml中设置android:configChanges="orientation|screenSize

1.2.2. onConfigurationChanged的使用

首先:权限声明

<uses-permission Android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>

其次:声明Activity要捕获的事件类型

如:Android:configChanges="orientation|keyboard"

最后:重写ActivityonConfigurationChanged方法,如:

 Android开发艺术探究(一):Activity的生命周期和启动模式

1.2.2.1. configChanges可选属性

“mcc“

The IMSI mobile country code (MCC) has changed — that is, a SIM hasbeen detected and updated the MCC.移动国家号码,由三位数字组成,每个国家都有自己独立的MCC,可以识别手机用户所属国家。

“mnc“

The IMSI mobile network code (MNC) has changed — that is, a SIM hasbeen detected and updated the MNC.移动网号,在一个国家或者地区中,用于区分手机用户的服务商。

“locale“

The locale has changed — for example, the user has selected a new language that text should be displayed in.用户所在地区发生变化。

“touchscreen“

The touchscreen has changed. (This should never normally happen.)

“keyboard“

The keyboard type has changed — for example, the user has plugged in an external keyboard.键盘模式发生变化,例如:用户接入外部键盘输入。

“keyboardHidden“

The keyboard accessibility has changed — for example, the user has slid the keyboard out to expose it.用户打开手机硬件键盘

“navigation“

The navigation type has changed. (This should never normally happen.)

“orientation“

The screen orientation has changed — that is, the user has rotated the device.设备旋转,横向显示和竖向显示模式切换。

“fontScale“

The font scaling factor has changed — that is, the user has selected a new global font size.全局字体大小缩放发生改变

1.2.3. onNewIntent的使用

Activity已经存在,如LaunchModeSingleTop或者singleTask时,再次打开该Activity,通过执行onNewIntent传递数据。

生命周期为:onPause->onStop->onNewIntent->onRestart->onStart->onResume

1.2.4. 情况2:资源不足导致优先级低的Activity被杀死

该情况下也会执行onSaveInstanceStateonRestoreInstanceStae方法保存与恢复数据。

1.2.4.1. 前台Activity优先级最高

1.2.4.2. 可见但非前台的Activity优先级次之

1.2.4.3. 后台Activity优先级最低

2. Activity的启动模式

2.1. ActivityLaunchMode

2.1.1. Standard

标准模式:每次启动一个Activity就会创建一个新的实例。该模式下,一个任务栈可以有多个实例,每个实例也可以属于不同的任务栈。谁启动这个Activity,这个Activity就会属于那个Activity属于的那个任务栈。

2.1.2. singleTop

栈顶复用模式:如果新的Activity已经位于任务栈的栈顶,就不会重新被创建,而是执行onNewIntent方法接受参数。如果新的Activity不在栈顶,则会被再次创建。

2.1.3. singleTask

栈内复用模式:这是一种单例模式,如果新的Activity已经存在于该栈内,则不会被重新创建,而是执行onNewIntent方法接收参数。此时该Activity会被置于栈顶,它之前的Activity会被踢出该任务栈。

2.1.4. singleInstance

单实例模式:这是一种加强版的singleTask模式。该模式下的Activity单独占用一个任务栈,系统在创建该

Activity时,会为它创建一个新的任务栈。后续的请求均不会创建新的Activity,除非这个任务栈被系统销毁。

执行onNewIntent方法接收参数。

2.2. ActivityFlags

ActivityFlags有很多,这里只分析一些常用的标记位。

2.2.1. Intent.FLAG_ACTIVITY_NEW_TASK

指定Activity的启动模式为“singleTask

2.2.2. Intent.FLAG_ACTIVITY_SINGLE_TOP

指定Activity的启动模式为“singleTop

2.2.3. Intent.FLAG_ACTIVITY_CLEAR_TOP

具有此标识位的Activity创建时,和它在同一个任务栈中的并且在它之上的Activity都要出栈。它一般与Intent.FLAG_ACTIVITY_NEW_TASK一起使用。

2.2.4. Intent.FLAG_ACTIVITY_NO_HISTORY

具有该标识位的Activity,启动新的Activity后就会被销毁,不会保留在任务栈中。

2.2.5. Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

使用该标记符的Activity不会出现在Activity列表中,也即我们从最近应用里面查看不到我们启动的这个activity。等同于在xml指定Activity的属性:android:excludeFromRecents=true

 

2.3. 启动模式的使用方式

2.3.1. 通过配置AndroidManifest.xmlActivity指定启动模式

 Android开发艺术探究(一):Activity的生命周期和启动模式

2.3.2. 通过Intent中设置标识位(addFlags方法)为Activity指定启动模式

 Android开发艺术探究(一):Activity的生命周期和启动模式

3. IntentFilter的匹配规则

Intentfilter:意图过滤器。它包括actioncategorydata

启动Activity包括两种方式,显式调用和隐式调用。

显式调用:明确指定被启动对象的组件信息,包括包名与类名,最为常用。

隐式调用:通过匹配目标组件的IntentFilter中所设置的过滤信息,如果不匹配则无法启动目标Activity

下面为过滤规则的示例:

 Android开发艺术探究(一):Activity的生命周期和启动模式

一个匹配列表中的actioncategorydata可以有多个,只有一个Intent同时匹配action类别、category类别、data类别时才算完全匹配,只有完全匹配才能启动该Activity。另外,一个Activity可以有多个匹配列表(intent-filter),只要匹配一个就可以成功启动该Activity

 

3.1. Action

3.1.1. Action的匹配规则

Action是一个字符串。一个过滤规则可以有多个actionIntent中的Action能够和过滤规则中的任一个action相同即可匹配成功。如果Intent中没有action则匹配失败。另外,action区分大小写,大小写不同字符串相同也会匹配失败。

3.1.2. 系统预定义的Action

"android.intent.action.MAIN"------------------动作:作为主入口点启动,不需要数据。

"android.intent.action.CALL"-------------------动作:拨打电话,被呼叫的联系人在数据中指定。

详细查看:http://blog.csdn.net/mc_hust/article/details/46300929

 

3.2. Category

3.2.1. Category的匹配规则

Category是一个字符串。Category的匹配规则与action不同,Intent中可以没有category,但是如果有,不管有几个,每个Category都必须与过滤规则中的Category相对应。

为什么Intent中可以没有Category呢?因为系统在调用startActivitystartActivityForResult时,默认加了“android.intent.category.DEFAULT”,这样就匹配了前面示例的第三个Category。同时,为了Activity能被隐式调用,必须在intent-filter中加入“android.intent.category.DEFAULT”。

3.2.2. 系统预定义的Category

android.intent.category.DEFAULT----------------------------------默认的category

“android.intent.category.LAUNCHER”--------------------------------决定应用程序是否显示在程序列表里

...

3.3. Data

3.3.1. Data的匹配规则

Data的匹配规则和action类似,如果过滤规则中定义了data,那么Intent中也必须定义可匹配的Data

3.3.2. Data的定义语法

Data由两部分组成:mimeTypeURI :

 Android开发艺术探究(一):Activity的生命周期和启动模式

 

mimeType指媒体类型,比如image/jpegaudio/mpeg4-genericvideo/*等,可以表示图片、音频和视频等。

URI包含的东西比较多,结构为:

<scheme>://<host>:<post>/[<path>|<pathPrefix>|<pathPattern>]

Scheme:URI 的模式,如httpfilecontent等,如果不指定scheme,则整个uri无效

Hosturi的主机名,如www.baidu.com,如果不指定host,则整个uri无效

Porturi的端口号,如8080,只有指定了schemehostport才有意义。

PathpathPrefixpathPattern:这三个参数为路径信息。其中path为完整路径,pathPattern也是完整路径,不过它可以使用通配符’*’,’*’表示0个或任意个。pathPrefix为路径前缀。

3.4. Intent指定ActionCategorydata的方式

 Android开发艺术探究(一):Activity的生命周期和启动模式