《Android开发艺术探索》读书笔记1.Activity的生命周期和启动模式

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

1.1. 典型情况下的生命周期分析

Activity启动
    ↓
onCreate
    ↓
onStart ←-- onRestart
    ↓           ↑
onResume        |
    ↓           |
Activity运行    |
    ↓           |
onPause         |
    ↓           |
onStop ----------
    ↓
onDestroy
    ↓
Activity销毁

当新启动一个Activity的时候,旧ActivityonPause会先执行,然后才会启动新的Activity

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

情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建
比如说当前Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity就会被销毁并重新创建。

Activity                         Activity
 ↓意外情况                            ↓
onSaveInstanceState -- 重新创建 → onCreate
 ↓                                   ↓
onDestory                        onRestoreInstanceState

Activity在异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后恢复这些数据,比如文本框中用户输入的数据、ListView滚动位置等,这些View相关的状态系统都能够默认恢复。和Activity一样,每个View都有onSaveInstanceStateonRestoreInstanceState这两个方法,看一下它们的具体实现,就能知道系统能够自动为每个View恢复哪些数据。

情况2:资源内存不足导致低优先级的Activity被杀死
Activity按照优先级从高到低,可以分为如下三种:
(1)前台Activity——正在和用户交互的Activity,优先级最高。
(2)可见但非前台Activity——比如Activity中弹出了一个对话框,导致Activity可见但是位于后台无法和用户直接交互。
(3)后台Activitiy——已经被暂停的Activity,比如执行了onStop,优先级最低。
当系统内存不足时,系统就会按照上述优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceStateonRestoreInstanceState来存储和恢复数据。

系统配置中有很多内容,如果当某项内容发生改变后,我们不想系统重新创建Activity,可以给Activity指定configChanges属性。比如不想让Activity在屏幕旋转的时候重新创建,就可以给configChanges属性添加orientation这个值,如下所示。

android:configChanges="orientation"

2. Activity的启动模式

(读者注:可以参考Android官方文档:任务和返回栈  |  Android Developers)

2.1.ActivityLaunchMode

目前有四种启动模式:
(1)standard:标准模式,这也是系统的默认模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。(ABCD+D=ABCDD)
(2)singleTop:栈顶复用模式,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数可以取出当前请求的信息。(ABCD+D=ABCD)
(3)singleTask:栈内复用模式。这是一种单实例模式,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,且栈内所有在此Activity上面的Activity全部出栈。和singleTop一样,系统也会回调其onNewIntent。(ADBC+D=AD)
(4)singleInstance:单实例模式。具有此种模式的Activity只能单独地位于一个任务栈中。由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。(A+A=A)

android:taskAffinity参数标识了一个Activity所需要的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名。TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。当TaskAffinitysingleTask启动模式配对使用的时候,它是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。

Activity指定启动模式有两种方法,第一种是通过AndroidManifestActivity指定启动模式,另一种情况是通过在Intent中设置标志位来为Activity指定启动模式,比如:

Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

第二种方式的优先级要高于第一种,另外,上述两种方式在限定范围上有所不同,比如,第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识,而第二种方式无法为Activity指定singleInstance模式。

2.2. ActivityFlags

FLAG_ACTIVITY_NEW_TASK:为Activity指定singleTask启动模式
FLAG_ACTIVITY_SINGLE_TOP:为Activity指定singleTop启动模式
FLAG_ACTIVITY_CLEAR_TOP:具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。如果被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标记的Activity不会出现在历史Activity的列表中,等同于在XML中指定Activity的属性android:excludeFromRecents="true"

3. IntentFilter的匹配规则

启动Activity分为两种,显式调用和隐式调用。隐式调用需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息。
为了匹配过滤列表,需要同时匹配过滤列表中的actioncategorydata信息。另外,一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity

1.action的匹配规则
action是一个字符串,系统预定义了一些action,同时我们也可以在应用中定义自己的actionaction的匹配要求Intent中的action存在且必须和过滤规则中的其中一个action相同。

2.category的匹配规则
category是一个字符串,系统预定义了一些category,同时我们也可以在应用中定义自己的categorycategory的匹配规则要求Intent中如果含有category,那么所有的category都必须和过滤规则中的其中一个category相同。系统在调用startActivity或者startActivityForResult的时候会默认为Intent加上android.intent.category.DEFAULT这个category,所以Intent不设置category也可以匹配,为了activity能够接收隐式调用,必须在intent-filter中指定android.intent.category.DEFAULT这个category

3.data的匹配规则
data的语法如下所示:


data由两部分组成,mimeTypeURImimeType指媒体类型,比如image/jpegaudio/mpeg4-genericvideo/*等,可以表示图片、文本、视频等不同的媒体格式,而URI中包含的数据就比较多了,下面是URI的结构:

://:/[||]

SchemeURI的模式,比如httpfilecontent等,如果URI中没有指定schemeURI是无效的。
HostURI的主机名,比如www.baidu.com,如果host未指定,URI是无效的。
PortURI中的端口号,比如80。仅当URI中指定了schemehost参数的时候port参数才是有意义的。

data的匹配规则和action类似,它也要求Intent中必须含有data数据,并且data数据能够完全匹配过滤规则中的某一个data。 如下过滤规则:


	
	...

这种规则指定了媒体类型为所有类型的图片,虽然没有指定URI,但是却有默认值contentfile。也就是说,Intent中的URI部分的schema必须为content或者file才能匹配。示例:

intent.setDataAndType(Uri.parse("file://abc"), "image/png");

通过隐式方式启动一个Activity的时候,可以做一下判断,方法有两种:采用PackageManagerresolveActivity方法或者IntentresolveActivity方法,如果它们找不到匹配的Activity就会返回null

你可能感兴趣的:(读书笔记)