Activity详解(二)——Activity的四种启动模式

来源:互联网 发布:乐视下载软件 编辑:程序博客网 时间:2024/05/19 09:40

一、前言

在学习Activity启动模式之前,我们先来简单了解一下Activity栈:栈都是先进后出的,Activity栈也不例外,启动一个Activity,系统就会创建一个Activity的实例放入到Activity栈中,当销毁一个Activity的时候,系统就会从Activity栈中移除掉相应的Activity实例。这里就会有一个问题,每次启动Activity都创建一个实例压入Activity栈中,就会消耗更多的内存,也不利于Activity的复用,所有就有了启动模式来规定Activity的启动方式。
可以用命名adb shell dumpsys activity来查看当前Activity栈中的Activity实例情况。

二、四种启动模式

1.Standard

标准启动模式。该启动模式为Activity启动的默认模式,也就是说我们平常创建一个Activity的时候,就是以这种模式启动。用这种模式启动的Activity会在它想要去的Activity栈中创建一个实例,而不论这个栈中是否已经含有这个Activity的实例。什么是它想要去的Activity栈呢?简单来讲,就是哪个Activity启动它的,它就会想去那个Activity所在的栈中。例如,Activity A启动了Activity B,而Activity A在ActivityA栈中,所以Activity B也就会想要去Activity A所在的栈——ActivityA栈中。

2.singleTop

栈顶复用模式。用该模式启动的Activity,如果在想要去的栈中的栈顶为该Activity的实例,那么就不会再次创建该Activity的实例,而是回调Activity的onNewIntent方法来做处理。需要注意的是,这个Activity的onCreate、onSt、方法不会被系统调用,因为它并没有发生改变。举个例子,假设目前有一个Activity栈,栈内的情况为ABCD,其中ABCD为四个Activity,A位于栈底,D位于栈顶,A、D的启动模式为SingeTop,这时候如果要启动D,那么栈内的情况依然是ABCD,如果要启动A,那么栈内的情况就会变成ABCDA。

3.singleTask

栈内复用模式。该模式和singleTop较为类似,用该模式启动的Activity,如果在想要去的栈中的栈顶为该Activity的实例,也同样不会再次创建该Activity的实例,而是调用onNewIntent。但是有一种不同,如果在该Activity栈中已经有了该Activity的实例(不是位于栈顶),那么系统就会复用该Activity的实例,把位于该Activity上面的其他Activity实例给清除掉,同时把该Activity调到栈顶来(把位于该Activity上面的其他Activity清除掉就相当于把该Activity调用栈顶了)。而singleTop模式的Activity,不会清除掉位于其上面的的其他的Activity实例。这是因为singleTask启动的Activity默认具有clearTop效果。还是用2中的那个例子,假设此时A、D的启动模式为singleTask,这时候如果要启动D,情况和2一样,依然是ABCD,而如果要启动A,那么栈内的情况就完全不一样了,变成了A,把A上面的Activity实例都clear掉了。注意,此时这个例子假设所有Activity想要去栈都是ABCD所在的栈,是因为TaskAffinity属性,至于为什么,后文再分析。

4.singleInstance

单实例模式。这种模式可以理解为是一种加强版的singleTask,利用该模式启动的Activity,如果系统中已经存在该实例,则会重用该Activity实例,然后回调onNewIntent方法;如果系统中还没有该Activity实例,则会创建一个新的Activity栈一个该Activity实例并把该Activity实例压入到栈中。这个栈有一个特点,就是只能容纳这个Activity,不能够容纳其他Activity实例,也就是说用该模式启动的Activity会独占一个Activity栈。

三、TaskAffinity

上文中数次说到Activity想要去的Activity栈为启动其的那个Activity所在的Activity栈。但是如果想把Activity启动到别的Activity栈内呢?这里需要用到一个参数:TaskAffinity,TaskAffinity可理解为喜爱的任务,也就是想去的Activity栈。通过给Activity指定TaskAffinity属性,可以改变Activity想要去的Activity栈,将Activity启动到TaskAffinity属性指定的Activity栈中。其实TaskAffinity标识的是一个Activity想要去的任务栈的名字,默认情况下,所有Activity想要去的Activity栈名字为应用的包名。通过指定与包名不同的名字,可以将Activity启动到别的栈去。这也解释了二.3中的那个疑问了。
注意:

  1. 该属性要和singleTask启动模式才有意义,和其他三种模式混在一起使用是没有意义的。因为其他三种启动模式启动的Activity都会运行在启动它的那个Activity所在的栈中,而singleTask启动模式启动的Activity会运行在TaskAffinity属性所指定的栈中。
  2. 这个TaskAffinity属性的值为类似包名格式的字符串(但要与包名不同),如包名为com.google,则TaskAffinity的值可为com.google1等等。

四、如何给Activity指定启动模式

1.通过AndroidManifest.xml为Activity指定启动模式,如下

<activity    android:name="com.ryg.chapter_1.SecondActivity"    android:configChanges="screenLayout"    android:launchMode="singleTask"    ..../>

2.在intent中设置标志位来为Activity设置启动模式

Intent intent = new Intent();intent.setClass(MainActivity.this, SecondActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);

这两种启动方式的区别:
1. 优先级上,第二种的优先级要高于第一种方式,当两种方式都存在的时候,以第二种方式为准。
2. 作用范围不同,例如第一种方式不能够直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识(清除上边Activity实例标识),而第二种方式不适合于singleInstance启动模式。

五、标志位

在上面第二种启动方式中,出现了一个Flags,Activity的Flags有很多,但是大部分情况下不需要使用标志位,所以了解一下即可。
有一个比较常见的Flags为FLAG_ACTIVITY_NEW_TASK,对于有在Service中启动Activity经验的童鞋们,大概都会遇到过这个错误:

Calling startActivity from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag.

这个错误相信读者一定不会陌生,这是因为Activity会默认进入到启动它的Activity所在的Activity栈中,但是对于非Activity类型的Context(如Service)并没有所谓的Activity栈,此时就会出问题。解决方法是为待启动的Activity加上一个flags:FLAG_ACTIVITY_NEW_TASK,这是就会为待启动的Activity创建一个新的Activity栈。加上该flags启动的Activity实际上相当于用singleTask启动模式启动Activity。

六、结语

其实实际开发中,Activity的启动模式应用得不多,大部分都以默认的standard模式启动。但是我们还是需要了解其原理的,万一以后真的用到了呢。

0 0
原创粉丝点击