Android中的Activity详解--启动模式与任务栈

目录

  • Activity
  • 生命周期
  • 任务栈
  • 启动模式
  • Intent Flag
  • taskAffinity属性

1.Activity

activity的简单介绍就不写了,作为最常用的四大组件之一,肯定都很熟悉其基本用法了。

2.生命周期

首先,是都很熟悉的一张图,即官方介绍的Activity生命周期图.


Activity生命周期图

情景:打开某个应用的的FirstActivity调用方法如下:
由于之前已经很熟悉了,这里就简单贴一些图。


Paste_Image.png

按下返回键:


Paste_Image.png

重新打开并按下home键:


Paste_Image.png

再重新打开:


Paste_Image.png

在其中打开一个DialogActivity(SecondActivity)


Paste_Image.png

按下返回:


Paste_Image.png

修改SecondAcitvity为普通Activity,依旧是上述操作:


Paste_Image.png

这里强调一下onSaveInstanceState(Bundle outState)方法的调用时机:
当Activity有可能被系统杀掉时调用,注意,一定是被系统杀掉,自己调用finish是不行的。
测试如下:FirstActivity启动SecondActivity:

Paste_Image.png

如果SecondActivity是android:theme="@android:style/Theme.Dialog"那么:
Paste_Image.png

如果FirstActivity启动SecondActivity后自己调用了finish方法:
Paste_Image.png

也就是说,只要一个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:


Paste_Image.png

当只有一个FirstActivity时堆栈情况:


Paste_Image.png

当在FirstActivity中启动FirstActivity时堆栈情况:
Paste_Image.png

这就很显然了,任务栈中一共有两个FirstActivity,即表示每次启动FirstActivity都是创建了一个新的实例。
  • singleTop

此种模式下,Activity在启动时会进行判断,如果当前的App的栈顶的Activity即正在活动的Activity就是将要启动的Activity,那么就不会创建新的实例,直接使用栈顶的实例。
测试,设置FirstActivity为此启动模式,多次点击FirstActivity中的启动FirstActivity的按钮查看堆栈情况:
(其实点击按钮没有启动新Activity的动画就可以看出并没有启动新Activity)

Paste_Image.png

果然,堆栈中只有一个FirstActivity
如果我在FirstActivity中启动了SecondActivity,此时FirstActivity不就不在栈顶了么,此时我再启动FirstActivity会怎样呢?
测试如下:
Paste_Image.png

很好的验证了,只有在栈顶时,才不会创建新实例。
这种启动模式很适用于接收到消息之后进行显示的界面,总不能每次来消息都创建新实例,那一次来个十几条消息岂不是爆炸了。
在此种模式下,在不创建新的实例的时候,会调用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:

Paste_Image.png

然后在ThirdActivity中启动SecondActivity(注意不是返回,而是启动):
Paste_Image.png

果然,SecondActivity上的ThirdActivity被清掉了
2.如果是其他应用的Activity启动的本应用中此Activity,那么
- 本应用未启动时,在另一个应用的ActivityY中启动SecondActivity:
Paste_Image.png

显然,此时这个SecondActivity是在一个单独的任务栈中的,且是处于前台的,按下返回键,SecondActivity结束,返回到ActivityY。
- 本应用已经启动了,在后台运行,任务栈中是FirstActivity和SecondActivity,在另一个应用的ActivityY中启动此Activity,此时任务栈的状态:
Paste_Image.png

两个任务栈,每个栈中都有两个Activity。
注意,此时如果按下返回键,会出现什么情况呢,到底是返回到ActivityY,还是返回到FirstActivity?
结果如下:
Paste_Image.png

前台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

结果:


Paste_Image.png

显然,启动了两次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

任务栈信息如下:


Paste_Image.png

结果很显然了。
测试:在上述基础上,在ActivityX中进行跳转到ActivityY,ActivityY不指定启动模式和taskAffinity。结果如下:


Paste_Image.png

发现ActivityY在gsq.test任务栈中,这是由于其启动模式是Standard,也就是在启动这个Activity的所在的任务任务栈中。
再将ActivityY指定启动模式singleTask:
Paste_Image.png

这样就没问题了,ActivityY在一个新的任务栈中,名称为包名。
这时从ActivityY跳转到SecondActivity,那应该是gsq.test任务栈只有SecondActivity,ActivityX已经没有了。因为其启动模式是singleTask,在启动它时发现已经有一个实例存在,就把它所在的任务栈上面的Activity都清空了并将其置于栈顶。

还有一点需要提一下,在上面,FirstActivity是App1的lunch Activity,但是由于SecondActivity并没有指定MAIN和LAUNCHER过滤器,故在FirstActivity跳转到SecondActivity时,按下home键,再点开App1,回到的是FirstActivity。

大致就先写这么多吧,好像有点长,废话有点多,估计也有错别字,不要太在意~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容