目录
- Activity
- 生命周期
- 任务栈
- 启动模式
- Intent Flag
- taskAffinity属性
1.Activity
activity的简单介绍就不写了,作为最常用的四大组件之一,肯定都很熟悉其基本用法了。
2.生命周期
首先,是都很熟悉的一张图,即官方介绍的Activity生命周期图.
情景:打开某个应用的的FirstActivity调用方法如下:
由于之前已经很熟悉了,这里就简单贴一些图。
按下返回键:
重新打开并按下home键:
再重新打开:
在其中打开一个DialogActivity(SecondActivity)
按下返回:
修改SecondAcitvity为普通Activity,依旧是上述操作:
这里强调一下onSaveInstanceState(Bundle outState)方法的调用时机:
当Activity有可能被系统杀掉时调用,注意,一定是被系统杀掉,自己调用finish是不行的。
测试如下:FirstActivity启动SecondActivity:
如果SecondActivity是
android:theme="@android:style/Theme.Dialog"
那么:如果FirstActivity启动SecondActivity后自己调用了finish方法:
也就是说,只要一个Activity转为后台,那么就会调用此方法,因为其有可能被系统杀掉,其中存的Bundle对象就是用来存储数据的,这个也就是onCreate方法中Bundle对象参数savedInstanceState的由来。
3.Acitvity任务栈
一个App会包含很多个Activity,多个Activity之间通过intent进行跳转,那么原始的Activity就是使用栈这个数据结构来保存的。
Task
A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack (theback stack), in the order in which each activity is opened.
即若干个Activity的集合的栈表示一个Task。
当App启动时如果不存在当前App的任务栈就会自动创建一个,默认情况下一个App中的所有Activity都是放在一个Task中的,但是如果指定了特殊的启动模式,那么就会出现同一个App的Activity出现在不同的任务栈中的情况,即会有任务栈中包含来自于不同App的Activity。
4.启动模式
-
standard
标准模式,在不指定启动模式的情况下都是以此种方式启动的。每次启动都会创建一个新的Activity实例,覆盖在原有的Activity上,原有的Activity入栈。
测试如下:在FirstActivity中启动FirstActivity:
当只有一个FirstActivity时堆栈情况:
当在FirstActivity中启动FirstActivity时堆栈情况:
这就很显然了,任务栈中一共有两个FirstActivity,即表示每次启动FirstActivity都是创建了一个新的实例。
-
singleTop
此种模式下,Activity在启动时会进行判断,如果当前的App的栈顶的Activity即正在活动的Activity就是将要启动的Activity,那么就不会创建新的实例,直接使用栈顶的实例。
测试,设置FirstActivity为此启动模式,多次点击FirstActivity中的启动FirstActivity的按钮查看堆栈情况:
(其实点击按钮没有启动新Activity的动画就可以看出并没有启动新Activity)
果然,堆栈中只有一个FirstActivity
如果我在FirstActivity中启动了SecondActivity,此时FirstActivity不就不在栈顶了么,此时我再启动FirstActivity会怎样呢?
测试如下:
很好的验证了,只有在栈顶时,才不会创建新实例。
这种启动模式很适用于接收到消息之后进行显示的界面,总不能每次来消息都创建新实例,那一次来个十几条消息岂不是爆炸了。
在此种模式下,在不创建新的实例的时候,会调用onNewIntent()方法。
总结:栈顶的Activity只会有一个实例,在栈顶的情况下重复启动该Activity只会复用该Activity,而不会创建一个新的,除了栈顶的Activity外,其他的和standard类似,每次启动都会被创建一个新的实例。
onNewIntent(Intent intent)方法介绍
官方解释如下:
- This is called for activities that set launchMode to "singleTop" in
* their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}
* flag when calling {@link #startActivity}. In either case, when the
* activity is re-launched while at the top of the activity stack instead
* of a new instance of the activity being started, onNewIntent() will be
* called on the existing instance with the Intent that was used to
* re-launch it.
*
* <p>An activity will always be paused before receiving a new intent, so
* you can count on {@link #onResume} being called after this method.
*
* <p>Note that {@link #getIntent} still returns the original Intent. You
* can use {@link #setIntent} to update it to this new Intent.
*
* @param intent The new intent that was started for the activity.
大意就是:
对于使用singleTop启动或Intent.FLAG_ACTIVITY_SINGLE_TOP启动的Activity,当该Activity被重复启动(注意一定是re-launched,第一次启动时不会调用)时就会调用此方法。
且调用此方法之前会先暂停Activity也就是先调用onPause方法。
而且,即使是在新的调用产生后此方法被调用,但是通过getIntent方法获取到的依旧是以前的Intent,可以通过setIntent方法设置新的Intent。
方法参数就是新传递的Intent.
-
singleTask
1.如果是同一个App中启动某个设置了此模式的Activity的话,如果栈中已经存在该Activity的实例,那么就会将该Activity上面的Activity清空,并将此实例放在栈顶。
测试:SecondActivity启动模式设为singleTask,启动三个Activity:
然后在ThirdActivity中启动SecondActivity(注意不是返回,而是启动):
果然,SecondActivity上的ThirdActivity被清掉了
2.如果是其他应用的Activity启动的本应用中此Activity,那么
- 本应用未启动时,在另一个应用的ActivityY中启动SecondActivity:
显然,此时这个SecondActivity是在一个单独的任务栈中的,且是处于前台的,按下返回键,SecondActivity结束,返回到ActivityY。
- 本应用已经启动了,在后台运行,任务栈中是FirstActivity和SecondActivity,在另一个应用的ActivityY中启动此Activity,此时任务栈的状态:
两个任务栈,每个栈中都有两个Activity。
注意,此时如果按下返回键,会出现什么情况呢,到底是返回到ActivityY,还是返回到FirstActivity?
结果如下:
前台Activity竟然变成了FirstActivity!继续按下返回键,就会返回到ActivityY,ActivityX,然后退出。
也就是说,在ActivityY启动了SecondActivity时,连带着SecondActivity的任务栈也被带到了前台。
那么我不禁要问了,如果SecondActivity启动模式是默认的,会不会是此种情况呢?,其实按照我们前面学的,按照分析的话,应该是SecondActivity在ActivityY所在的App所对应的任务栈中创建一个新的实例,跟原本的SecondActivity所在后台任务栈没有一毛钱关系。
- 本应用已经启动了三个Activity,任务栈中是FirstActivity和SecondActivity和ThirdActivity,此时再由ActivityY启动:
那么稍微思考一下就可以肯定运行结果跟上面是完全相同的,因为在跳转到SecondActivity时,其上面的Activity已经被清空了。
-
singleInstance
这个模式就很好记,以此模式启动的Activity会存放在一个单独的任务栈中,且只会有一个实例。
测试:SecondActivity启动模式设为singleInstance
FirstActivity->SesondActivity->ThirdActivity->SecondActivity->ThirdActivity
结果:
显然,启动了两次ThirdActivity任务栈中就有两个实例,而SecondActivity在另外一个任务栈中,且只有一个。
5.Intent Flag设置启动模式
在使用Intent启动一个Activity时可以设置启动该Activity的启动模式:
这个属性有很多,大致列出几个:
-
Intent.FLAG_ACTIVITY_NEW_TASK
每个启动的Activity都在一个新的任务栈中
-
Intent.FLAG_ACTIVITY_SINGLE_TOP
singleTop
-
Intent.FLAG_ACTIVITY_CLEAR_TOP
singleTask
-
Intent.FLAG_ACTIVITY_NO_HISTORY
用此种方式启动的Activity,在它启动了其他Activity后,会自动finish.
6.taskAffinity属性
官方文档介绍如下:
The task that the activity has an affinity for. Activities with the same affinity conceptually belong to the same task (to the same "application" from the user's perspective). The affinity of a task is determined by the affinity of its root activity.The affinity determines two things — the task that the activity is re-parented to and the task that will house the activity when it is launched with the FLAG_ACTIVITY_NEW_TASK flag.
By default, all activities in an application have the same affinity. You can set this attribute to group them differently, and even place activities defined in different applications within the same task. To specify that the activity does not have an affinity for any task, set it to an empty string.
If this attribute is not set, the activity inherits the affinity set for the application (see the<application>element's taskAffinity.
The name of the default affinity for an application is the package name set by the<manifest>element.
大意如下:
这个属性表示的是一个Activity对任务栈的亲和度。有相同的affinity的Activity属于同一个Task,即affinity相同的Activity会被加入同一任务栈。一个任务栈的affinity由其affinity值确定或是其根Activity的affinity确定。这个属性决定两件事,①Activity被re-parented时的任务栈,②以FLAG_ACTIVITY_NEW_TASK启动的Activity所在的任务栈。
默认情况下,同一个应用内的所有的Activity都拥有相同的affinity,你可以通过设置这个值来给Activity分组,甚至将不同应用的Activity放在相同的任务栈中。为了表明一个Activity对任何一个任务栈都不具有亲和力,那么将其设为空字符串。
如果这个值没有设置,那么就默认使用application标签下的这个值。
默认的affinity值为manifest标签下设置的包名。
这样看来的话,通俗易懂的讲,就是给每一个任务栈起个名,给每个Activity也起个名,在Activity以singleTask模式启动时,就检查有没有跟此Activity的名相同的任务栈,有的话就将其加入其中。没有的话就按照这个Activity的名创建一个任务栈。
测试:在App1中设置SecondActivity的taskAffinity为“gsq.test”,App2中的ActivityX的taskAffinity也设为“gsq.test”
FirstActivity->SesondActivity->home->ActivityX
任务栈信息如下:
结果很显然了。
测试:在上述基础上,在ActivityX中进行跳转到ActivityY,ActivityY不指定启动模式和taskAffinity。结果如下:
发现ActivityY在gsq.test任务栈中,这是由于其启动模式是Standard,也就是在启动这个Activity的所在的任务任务栈中。
再将ActivityY指定启动模式singleTask:
这样就没问题了,ActivityY在一个新的任务栈中,名称为包名。
这时从ActivityY跳转到SecondActivity,那应该是gsq.test任务栈只有SecondActivity,ActivityX已经没有了。因为其启动模式是singleTask,在启动它时发现已经有一个实例存在,就把它所在的任务栈上面的Activity都清空了并将其置于栈顶。
还有一点需要提一下,在上面,FirstActivity是App1的lunch Activity,但是由于SecondActivity并没有指定MAIN和LAUNCHER过滤器,故在FirstActivity跳转到SecondActivity时,按下home键,再点开App1,回到的是FirstActivity。
大致就先写这么多吧,好像有点长,废话有点多,估计也有错别字,不要太在意~~~