认知Activity启动模式

1.1 Activity的LaunchMode

activity启动模式基本知识不在描述。本文主要是在使用过的前提下进行了进一步的认知。首先任务栈大家都知道,先进后出、后进先出。如果任务栈没有activity了,那就会被系统所回收。Activity启动模式有四种:standard、singleTop、singleTask、singleInstance。

1.1.1 standard

标准模式、系统默认模式,每次启动均会创建实例压入栈中。
这里有一个点:编写类似下面代码启动activity会报错:

MyApplication.getInstance().startActivity(
   new Intent(MainActivity.this, AAy.class));

报错:

android.util.AndroidRuntimeException: 
 Calling startActivity() from outside of an Activity  context requires 
 the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

这是因为正常standard启动模式的activity默认会进入启动它的Activity所属的任务栈中(singleInstance除外),但是非activity的Context没有任务栈(任务栈是针对activity),所以出了上诉的错误和建议,加上以下设定即可:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

此时实际上以singleTask模式启动activity。

1.1.2 singleTop

这种模式简单来讲就是如果被启动activity位于栈定,那么就不会被重新创建,同时调用onNewIntent方法。
这个地方有一点小逻辑,比如两个Activity,A和B,A为singleTop模式,A启动了B,然后在B中这样子:

finish();
startActivity(new Intent(B.this, A.class));

你会发现这个时候复用了A,而且调用了A的onNewIntent方法。这种效果有点类似于startActivityForResult方法。再者如果这样子调用的话:

startActivity(new Intent(B.this, A.class));
finish();

是会创建一个新的A。其实也就是说finish方法有一个作用是把当前activity移除栈
如果正常B直接finish的话,A是会调用onRestart方法。

还有一种情况是:
有两个activity,A和B,A启动模式为singleTop,B启动模式为singleTask且设定taskAffinity="a.a",那么先启动A,然后A中启动B,B再启动A。这时候会发现虽然A和B归属两个不同的任务栈,但是在最后B再启动A时系统默认还是会遍历任务栈是否有需要的任务栈在存在,并且A是否位于顶部,有的话就会调用A的onNewIntent。但是如果A的启动模式为默认的,那么先启动A,然后A中启动B,B再启动A,那么就是第一个A是在默认的栈中,B和第二次启动A在栈a.a中。

1.1.3 singleTask

栈内复用模式,如果singleTask模式启动的activity存在一个栈中,则会被复用,并调用其onNewIntent方法。判断的的方式是如果要启动activity,首先会查找所需的栈是否存在,不存在则新建栈并放入activity,如果存在则会压入栈中。并且自带clearTop效果。

  • 如果存在任务栈S1,所需任务栈为S2,那么会创建S2并放入activity。
  • 如果存在任务栈S1,所需任务栈为S1,那么新建activity压入栈中,无论此时栈中是否有activity。
  • 如果存在任务栈S1,S1内有被启动的activity,那么会复用S1栈的activity并调用onNewIntent方法。此时会移除此activity上面的activity,移到栈顶。

这里有个点:如果MAIN的activity是singleTask模式的话会出现从桌面图标每次进入都会是mainActivity,而不是缩到后台的那个activity的情况。而且此时的mainActivity的并不是重新创建。不过主页直接是MAIN Activity的情况也不太多。

1.1.4 singleInstance

加强版的singleTask。会单独创建一个任务栈,并且只放被启动的activity。这里有一种情况,如果A启动B,B启动A,B启动模式为singleInstance。那么这时候会发现AA是在一个栈内,B一个栈。这是因为singleInstance时只允许存在一个B,而且从B启动的activity也不会和B在一个栈内。

下面说一种多任务栈的情况,如图:

多任务栈举例

两个任务栈,S1包含activity1和activity2,S2包含activity Y和activity X,且activity Y启动模式为singleTask。此时activity2启动activity Y,那么S2任务栈移到前台。此时按back按键,则activity Y移除栈,再按back按键,则移除activity X,此时S2任务栈没有activity了,则被回收。S1任务栈移到前台。

1.2 指定activity启动模式

两种方式:

<activity
    android:name=".AAy"
    android:launchMode="singleInstance" />

Intent intent = new Intent(MainActivity.this, AAy.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

区别:

  • 1、优先级为第二种最高
  • 2、使用范围不同,第一种无法直接为activity设定FLAG_ACTIVITY_CLEAR_TOP,第二种无法为activity设定singleInstance。

1.3 任务栈

默认所有activity所在的栈名为应用的包名。自定义的话可以在manifest中设定,如;

android:taskAffinity="a.a"

比如在application中设定,那么任务栈的名称就变成了".a.a"

  Stack #1:
    Task id #3474
      TaskRecord{596be1d #3474 A=a.a U=0 sz=2}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.ccddy.test/.MainActivity }
        Hist #1: ActivityRecord{11d80d35 u0 com.ccddy.test/.AAy t3474}
          Intent { cmp=com.ccddy.test/.AAy }
          ProcessRecord{3689f892 18292:com.ccddy.test/u0a196}
        Hist #0: ActivityRecord{210ce749 u0 com.ccddy.test/.MainActivity t3474}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.ccddy.test/.MainActivity }
          ProcessRecord{3689f892 18292:com.ccddy.test/u0a196}

查看任务栈方法:在AS中点击Terminal并输入命令:

adb shell dumpsys activity

找到ACTIVITY MANAGER ACTIVITIES,即可

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
    Task id #3474

但是如果在activity的标签中设定taskAffinity,并且activity启动模式例如为standard是没有意义的,而且栈的名称还是默认包名。1、但是如果taskAffinity和singleTask配对使用时,可以把singleTask放在指定的任务栈中(这种情况下和singleInstance是不一样的,如果A是这种模式,那么由A调起的activity是和A在一个任务栈内的)。2、taskAffinity和allowTaskReparenting结合使用:比如当一个应用A启动了应用B的某个activity后,如果这个activity的allowTaskReparenting为true时,然后按home按键回到桌面,点击B的桌面图标,这时候不是启动B的主activity,会启动被A启动的那个activity,也就是说把activity从A的任务栈中拉入了B中的任务栈中了。

1.4 Activity的Flags

标记为比较多,一般不会使用,而且有些是系统内部设定使用的。主要说明一下四种(不止四种哦):

FLAG_ACTIVITY_NEW_TASK

作用和singleTask一样

FLAG_ACTIVITY_SINGLE_TOP

作用和singleTop一样

FLAG_ACTIVITY_CLEAR_TOP

有点类似singleTask的clearTop效果。

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

具有这个标记的activity不会出现在最近运行任务的列表中(比如小米按菜单键那个运行中的APP列表)。和xml中设定android:excludeFromRecents="true"。

1.5 清理返回栈

如果用户长时间离开任务,则系统会清除所有 Activity 的任务,根任务除外。 当用户再次返回到任务时,仅恢复根 Activity。系统这样做的原因是,经过很长一段时间后,用户可能已经放弃之前执行的操作,返回到任务是要开始执行新的操作。
您可以使用下列几个 Activity 属性修改此行为:

  • alwaysRetainTaskState
    如果在任务的根 Activity 中将此属性设置为 "true",则不会发生刚才所述的默认行为。即使在很长一段时间后,任务仍将所有 Activity 保留在其堆栈中。

  • clearTaskOnLaunch
    如果在任务的根 Activity 中将此属性设置为 "true",则每当用户离开任务然后返回时,系统都会将堆栈清除到只剩下根 Activity。 换而言之,它与alwaysRetainTaskState正好相反。 即使只离开任务片刻时间,用户也始终会返回到任务的初始状态。

  • finishOnTaskLaunch
    此属性类似于 clearTaskOnLaunch但它对单个 Activity 起作用,而非整个任务。 此外,它还有可能会导致任何 Activity 停止,包括根 Activity。 设置为 "true"时,Activity 仍是任务的一部分,但是仅限于当前会话。如果用户离开然后返回任务,则任务将不复存在。

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

推荐阅读更多精彩内容