Activity启动
↓
onCreate
↓
onStart ←-- onRestart
↓ ↑
onResume |
↓ |
Activity运行 |
↓ |
onPause |
↓ |
onStop ----------
↓
onDestroy
↓
Activity销毁
当新启动一个Activity
的时候,旧Activity
的onPause
会先执行,然后才会启动新的Activity
。
情况1:资源相关的系统配置发生改变导致Activity
被杀死并重新创建
比如说当前Activity
处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity
就会被销毁并重新创建。
Activity Activity
↓意外情况 ↓
onSaveInstanceState -- 重新创建 → onCreate
↓ ↓
onDestory onRestoreInstanceState
当Activity
在异常情况下需要重新创建时,系统会默认为我们保存当前Activity
的视图结构,并且在Activity
重启后恢复这些数据,比如文本框中用户输入的数据、ListView
滚动位置等,这些View
相关的状态系统都能够默认恢复。和Activity
一样,每个View
都有onSaveInstanceState
和onRestoreInstanceState
这两个方法,看一下它们的具体实现,就能知道系统能够自动为每个View
恢复哪些数据。
情况2:资源内存不足导致低优先级的Activity
被杀死
Activity
按照优先级从高到低,可以分为如下三种:
(1)前台Activity
——正在和用户交互的Activity
,优先级最高。
(2)可见但非前台Activity
——比如Activity
中弹出了一个对话框,导致Activity
可见但是位于后台无法和用户直接交互。
(3)后台Activitiy
——已经被暂停的Activity
,比如执行了onStop
,优先级最低。
当系统内存不足时,系统就会按照上述优先级去杀死目标Activity
所在的进程,并在后续通过onSaveInstanceState
和onRestoreInstanceState
来存储和恢复数据。
系统配置中有很多内容,如果当某项内容发生改变后,我们不想系统重新创建Activity
,可以给Activity
指定configChanges
属性。比如不想让Activity
在屏幕旋转的时候重新创建,就可以给configChanges
属性添加orientation
这个值,如下所示。
android:configChanges="orientation"
Activity
的启动模式(读者注:可以参考Android官方文档:任务和返回栈 | Android Developers)
Activity
的LaunchMode
目前有四种启动模式:
(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
属性配对使用,在其他情况下没有意义。当TaskAffinity
和singleTask
启动模式配对使用的时候,它是具有该模式的Activity
的目前任务栈的名字,待启动的Activity
会运行在名字和TaskAffinity
相同的任务栈中。
给Activity
指定启动模式有两种方法,第一种是通过AndroidManifest
为Activity
指定启动模式,另一种情况是通过在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
模式。
Activity
的Flags
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"
。
IntentFilter
的匹配规则启动Activity
分为两种,显式调用和隐式调用。隐式调用需要Intent
能够匹配目标组件的IntentFilter
中所设置的过滤信息。
为了匹配过滤列表,需要同时匹配过滤列表中的action
、category
、data
信息。另外,一个Activity
中可以有多个intent-filter
,一个Intent
只要能匹配任何一组intent-filter
即可成功启动对应的Activity
。
1.action
的匹配规则
action
是一个字符串,系统预定义了一些action
,同时我们也可以在应用中定义自己的action
。action
的匹配要求Intent
中的action
存在且必须和过滤规则中的其中一个action
相同。
2.category
的匹配规则
category
是一个字符串,系统预定义了一些category
,同时我们也可以在应用中定义自己的category
。category
的匹配规则要求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
由两部分组成,mimeType
和URI
。mimeType
指媒体类型,比如image/jpeg
、audio/mpeg4-generic
和video/*
等,可以表示图片、文本、视频等不同的媒体格式,而URI
中包含的数据就比较多了,下面是URI
的结构:
://:/[||]
Scheme
:URI
的模式,比如http
、file
、content
等,如果URI
中没有指定scheme
,URI
是无效的。
Host
:URI
的主机名,比如www.baidu.com
,如果host
未指定,URI
是无效的。
Port
:URI
中的端口号,比如80
。仅当URI
中指定了scheme
和host
参数的时候port
参数才是有意义的。
data
的匹配规则和action
类似,它也要求Intent
中必须含有data
数据,并且data
数据能够完全匹配过滤规则中的某一个data
。 如下过滤规则:
...
这种规则指定了媒体类型为所有类型的图片,虽然没有指定URI
,但是却有默认值content
和file
。也就是说,Intent
中的URI
部分的schema
必须为content
或者file
才能匹配。示例:
intent.setDataAndType(Uri.parse("file://abc"), "image/png");
通过隐式方式启动一个Activity
的时候,可以做一下判断,方法有两种:采用PackageManager
的resolveActivity
方法或者Intent
的resolveActivity
方法,如果它们找不到匹配的Activity
就会返回null
。