Activity的启动模式

我们都知道,在默认情况下,当我们启动多个Activity的时候,这些Activity会被依次加入到任务栈中,当我们点击系统返回键,Activity又会按照后进先出的顺序依次出栈。
但是,如果我们多次启动同一个Activity,系统会重复创建多个实例,这样看起来是不是有点奇怪呢?系统设计者当然要考虑这个问题,因此启动模式应运而生。

目前Activity的启动模式有四种:standard、singleTop、singleTask和singleInstance。

  • standard 标准模式
    这是系统默认的启动模式,每次启动一个Activity,系统都会重新创建一个新的实例,并且加入到启动它的Activity所在的栈中。比如说在ActivityA中启动ActivityB(标准模式),那么ActivityB就会加入到ActivityA所处的任务栈中。

  • singleTop 栈顶复用模式
    在这种模式下,如果被启动的Activity已经位于栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数可以获取请求信息。如果新Activity不是位于栈顶,那么她依然会重建。

假设现在任务栈中内情况是ABCD,D位于栈顶,A位于栈底。这个时候要启动D,假如D的启动模式是singleTop,那么栈内情况依然是ABCD;假如D的启动模式是standard模式,那么栈内情况变成ABCDD。

  • singleTask 栈内复用模式
    这是一种单实例模式,在这种模式下,只要被启动Activity在一个栈内,那么多次启动这个Activity都不会发生重建。和singleTop一样,系统会调用其onNewIntent方法。
    这个模式可能情况相对要复杂一些。假如现在要启动一个模式为singleTask的ActivityD,如果系统不存在D想要的任务栈,那么系统会创建一个任务栈,并把D压入栈底;假如系统此时正好存在D需要的任务栈,则判断栈内是否有实例存在,如果有实例,则将D调到栈顶,如果此时D上有其他Activity,则全部弹出任务栈,如果不存在实例,则创建实例D并放入栈中。举个例子:

现有任务栈S1,栈内有实例ABC,C为栈顶,A为栈底,此时D以singleTask模式要求启动。
1、假设D所需栈为S2,由于系统内没有S2栈,所以会先创建S2任务栈,然后新建D实例并且压入S2栈中。
D启动完成后:S1-ABC,S2-D。
2、假设D所需任务栈为S1,由于S1已经存在并且栈内没有D的实例,因此系统会创建D实例并且压入S1栈中。
D启动完成后:S1-ABCD。
3、假设D所需任务栈为S1,并且此时S1内情况为ADBC,由于S1内已经有D的实例存在,所以系统直接将D调到栈顶,并且依次出栈C、B。这是因为singleTask模式默认具有clearTop的效果。
D启动完成前:S1-ADBC。
D启动完成后:S1-AD。

  • singleInstance 单实例模式
    这是一种加强的singleTask模式,它除了具体所有singleTask模式的特性之外,最重要的一点是,具有此模式的Activity只能单独位于一个任务栈中

假设Activity A的启动模式为singleInstance,当A启动后,系统会为它创建一个新的任务栈,并把A压入新的栈中。由于栈内复用的特性,后续的请求都不会创建新的Activity。


在singleTask模式中,多次提到Activity所需任务栈,那么如何指定一个Activity所需任务栈?这要从一个参数说起:TaskAffinity(任务相关性),这个参数对应的值就是Activity所需任务栈名字,Activity默认所需的任务栈名字就是应用包名。任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity处于暂停状态,用户可以将后台任务栈切换到前台。

  • 当TaskAffinity和singleTask模式配对使用的时候,它就是具有该模式的Activity当前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity属性相同的任务栈中。
  • 当TaskAffinity和allowTaskReparenting结合使用,这种情况比较复杂。当一个应用A启动了应用B的Activity,如果这个Activity的allowTaskReparenting为true,那么当应用B被启动,这个Activity会直接从应用A的任务栈转移到应用B的任务栈。

比如有两个应用A和B,A启动了B的Activity C,然后按Home键回到桌面,单击应用B的桌面图标,这个时候不会启动应用B的主Activity,而是直接显示被应用A启动的Activity C。也就是说C从A的任务栈转移到了B的任务栈中。

有两种方法可以为Activity指定启动模式,第一种是通过AndroidManifest.xml为Activity指定启动模式:

<activity
            android:name=".components.activity.LoginActivity"
            android:configChanges="orientation|keyboardHidden|navigation|screenSize"
            android:launchMode="singleTask"
            android:windowSoftInputMode="stateHidden|adjustPan" />

第二种是通过在Intent中设置标志位来为Activity指定启动模式:

Intent intent = new Intent(A.this, B.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);

这两种方式有一定的区别,在优先级上,第二种方式要高于第一种,如果同时存在,以第二种为准;两种方式在限定范围上也有所不同,第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识,第二种无法为Activity指定singleInstance启动模式。

Activity的一些常用标志位

  • FLAG_ACTIVITY_NEW_TASK
    作用是为Activity指定singleTask启动模式

  • FLAG_ACTIVITY_SINGLE_TOP
    作用是为Activity指定singleTop启动模式

  • FLAG_ACTIVITY_CLEAR_TOP
    具有此标志位的Activity启动时,位于其之上的Activity都要出栈。如果Activity的启动模式为standard模式,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。

    与standard连用.png

    与singleTop连用.png

    与singleTask连用.png

    注:图片来源https://blog.csdn.net/yztbydh/article/details/80450615

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    具有这个标志位的Activity不会出现在历史Activity列表中,当某些情况下我们不希望用户通过历史列表回到某个Activity的时候可以使用这个标志位,其对应在AndroidManifest中的属性为android:excludeFromRecents=“true”。

四种模式适用的应用场景:

  • standard 适用于大部分场景,每次创建新界面都新建一个Activity实例
  • singleTop 适用于同一界面展示不同内容的场景,例如点击推送消息打开消息详情界面,连续点击推送消息会重用第一次创建的实例(调用onNewIntent()方法),后续消息只是修改界面内容
  • singleTask 适用于App主界面,当用户回到主界面时,会把已经打开的其他界面销毁(调用onNewIntent()方法)
  • singleInstance 适用于手机系统应用界面,如闹铃提醒、来点显示等

————————————————————————————————————————————————
Standard:非以下特殊场景的普通Activity。

SingleTop:APP接收到多条推送消息,点开不同消息,均由同一实例展示。singleTop适合接收推送通知的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。

SingleTask:应用APP的主界面(Fragment的containerActivity)。singleTask适合作为程序入口点。例如淘宝的主界面,在淘宝陆续打开商品搜索界面、商品详细界面、订单界面、付款成功界面后,在付款成功界面一键返回主界面。

SingleInstance:如APP经常调用的拨打电话、系统通讯录、系统Launcher、锁屏键、来电显示等系统应用。singleInstance适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。

原文链接:https://blog.csdn.net/wq6ylg08/article/details/105911410
————————————————————————————————————————————————

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

推荐阅读更多精彩内容