Android LaunchMode的详解

西西说

作为一只安卓小白,还是愿意和大家分享我的探索旅程,那么就让我们先来一点来自Android launchMode的温馨提示吧~(≧▽≦)/~。

背景知识

“现在我的手中有一摞牌,但是我让你看到的只有一张。”

                                                          “其他牌去哪了呢?”

“其他张牌都被最上面这张牌挡住了呀。”

上面的这段话,很形象地解释了acitivity和任务栈的关系。

接下来我们首先了解一下任务——Task。

Task

  • Task 是activities的集合,通过back stack来管理,依靠先进后出队列来实现;
  • 每个task中都至少有一个activity,新实例出来的activity置于栈顶
  • Task可以被切换到后台

taskAffinity

  • taskAffinity 这个属性主要是决定持有每个activity属于哪个task。
  • 默认情况下,同一个包中的activity共享同一个affinity(任务共用性)。

launchMode

  • 用来设定activity应该如何启动
  • 主要有四种模式:
    • standard(default)
    • singleTop
    • singleTask
    • singleInstance

有没有需要改变默认设置的情况捏?

  • 有多个入口指向app
    • Launcher
    • Notification
    • Share Intent
  • “单例”Activity
    • 比如浏览器希望和很多个实例分享数据
    • 有啥可以改变呢?
    • activity的launchMode属性
    • Intent的flag

而在以上情况下,我们的默认启动模式都是无法满足的。

那么问题来了。。。启动模式哪家强(=@__@=)?
接下来,就让我们走近Android的4种启动模式吧~

Standard

  • 处于这种加载模式下的Activity可以有多个实例;
  • 它的实例可以住在不同的task中;
  • 一个task可以有多个它的实例

来,让我们一起做个实验吧

  • 实验配置:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xixi.standardlaunchmode" >
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".ActivityA"
            android:label="@string/app_name" />

        <activity 
            android:name=".ActivityB"
            android:taskAffinity="com.other" />
    application>

manifest>
  • 实验过程

  • 实验探析:

    • 怎么得出这个图的捏?
    • 首先我们可以先查看log
    • 接下来,我们再使用“adb shell dumpsys”来检测 Android的Activity任务栈
      
      通过上图我们可以看到standard模式的两个activity均在每次启动时不断实例化,但是我们知道activityB的taskAffinity是“com.other”呀,为啥没有起作用捏?~
    • 因为我们没有为intent添加参数:FLAG_ACTIVITY_NEW_TASK,加上以后会不会起作用捏?

      日志是什么样的捏?
  • 性能总结:
    • 在Lollipop之前,每发出一个intent,对应的activity就会被创建出来,新建出来的activity会放在那个发出intent的activity相同的任务栈中(这里,我们不考虑taskAffinity不同);
    • 在Lollipop版本时,来自相同application的activity,具体效果和之前一样,被创建出来就放在栈顶,但是如果是不同application的activity,被创建出来的activity会放在一个新的栈中(具体参见:http://inthecheesefactory.com/blog/understand-android-activity-launchmode/en)

SingleTop

  • 本质上来说,这个模式同Standard模式没有太大区别,只有在一个特殊的情况时会有例外。
  • 当back stack 的栈顶上已经存在这个模式activity的实例时,就不会被再实例,而是调用onNewIntent()来复用实例
    来,让我们一起做个实验吧,演示如下:
  • 实验配置:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xixi.standardlaunchmode" >
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".ActivityA"
            android:label="@string/app_name" />

        <activity 
            android:name=".ActivityB"
            android:taskAffinity="com.other" />
    application>

manifest>
  • 实验过程:
  • 实验探析:

首先 我们依然先看下日志:

接下来,进一步查看下任务栈:

  • 性能总结

    • 基本与standard 相同,只有在任务栈中已存在时,则不需要重新创建,而是调用onNewIntent()

    接下来,我们需要进入与前两种模式完全不一样的啦,稍事休息:

    AV8D,R U ready?嘿儿未够!

SingleTask

对于这个磨人的“小妖精”,官方文档中是这么描述的:

The system creates a new task and instantiates the activity at the root of the new task.
However, if an instance of the activity already exists in a separate task,`
the system routes the intent to the existing instance through a call to its onNewIntent() method,rather than creating a new instance. Only one instance of the activity can exist at a time.

而事实真的是这样么 还是先做实验吧

实验1: A的启动模式设为singleTask 3个Activity均在同一task中

  • 实验配置:
<activity android:name=".ActivityA" android:launchMode="singleTask" />
<activity android:name=".ActivityB" />
<activity android:name=".ActivityC" android:taskAffinity="com.others" />
  • 实验过程记录

    我们可以看到,再次启动A时,因为任务栈中已经存在了A的实例,所以为了把它提到栈顶来就把其他已经存在的Activity pop out了。
  • 实验日志任务栈变化:


    再次启动A后:


    日志:

    那么,如果B是singleTask A是standard会怎么样呢?

实验2: B的启动模式设为singleTask 3个Activity均在同一task中

  • 实验配置:
<activity android:name=".ActivityA" />
<activity android:name=".ActivityB" android:launchMode="singleTask" />
<activity android:name=".ActivityC" android:taskAffinity="com.others" />
  • 实验过程记录
  • 任务栈记录

    再次启动B后:

  • 小结:
    通过以上2个实验,我们可以看到:

    • 在同一个task(相当于在同一个app)中,若存在singleTask的activity,那么它会且只会被实例化1次。
    • 如果栈中已经存在它的实例了,它会直接通过onNewIntent来调用它,并且会把栈中在它上面的其他实例销毁掉;
    • 通过实验2我们可以知道,当singleTask Activity的实例不位于栈底,它是不会作为root Activity的,因为它并没有重新启动一个新的task,这一点说明官方文档与实际情况是有出入的。

实验3: A的启动模式设为singleTask 3个Activity 不在同一task中

  • 实验配置:
    与实验1相同;

    • 实验过程


    再次启动A后:

通过这个实验,我们发现ActivityA还在task 25中,并没有在新的task中实例化,并且再次启动它时,为了把它置于栈顶,原来在它上面的activity也被结束了。

  • 性能总结
    • Activity为singleTask启动模式的,有且只有1个实例;
    • 若位于同一task中的activity想要再次启动它,则在stack中位于它上面的Activity将会被全部结束,从而使它位于任务栈的栈顶;
    • 如果想要使它在新的task中启动,需要为它设置taskAffinity属性

SingleInstance

同SingleTask一样有且只有一个实例 那么区别在哪捏?

实验1: A的启动模式设为singleInstance 3个activity分别在不同的task中

  • 实验配置:
<activity android:name=".ActivityA" android:launchMode="singleInstance" />
<activity android:name=".ActivityB" />
<activity android:name=".ActivityC" android:taskAffinity="com.others" />
  • 实验过程:
  • 实验探析



    再次启动A后:

    那么日志是啥样的呢?

  • 小结:

    • singleInstance的activity是作为task的root acitivity,它所在的task中只能放它一个。

实验2: B的启动模式设为singleInstance 2个activity在不同的task中

  • 实验配置:
<activity android:name=".ActivityA" />
<activity android:name=".ActivityB" android:launchMode="singleInstance" />
<activity android:name=".ActivityC" android:taskAffinity="com.others" />
  • 实验过程

    再次启动B后:

  • 性能总结

    • Activity为singleInstance启动模式的,系统中有且只有1个实例;
    • 它是root Activity;
    • 它比较孤僻,并且坚决不可以忍受和其他activity共用1个task;
    • 简单来说:
    foreach task in the tasks{
      if(hasSingleInstanceActivity) {
        task.isUnique = true;
        task.activityCapacity = 1;
        singleInstance.isUnique = true;
        acitvity.isRootActivity = true;
      } 
    }

总结

  • Android launchMode:
    • standard:activity有很多实例,不同实例还可以位于不同task中;
    • singleTop:activity同standard基本相同,只有当栈顶已经有它的实例的时候,就不需要再实例化了;
    • singleTask: activity有且只有1个实例,其它activity发出intent需要启动它时,和它处于同一栈中的activity就会被结束掉,从而保证它位于栈顶;
    • singleInstance: 和singleTask很相像,但是它更为孤傲,也就是说整个系统中只存在一个存放它的task,这个task里也只存放它,而它也只有一个。

查阅资料

http://www.slideshare.net/RanNachmany/manipulating-android-tasks-and-back-stack
http://developer.android.com/guide/components/tasks-and-back-stack.html
http://inthecheesefactory.com/blog/understand-android-activity-launchmode/en
这里还有一个中文版哈Acitivity启动模式图文详解

http://blog.csdn.net/guolin_blog/article/details/41087993
http://blog.csdn.net/luoshengyang/article/details/6714543

你可能感兴趣的:(android)