Activity 深入——四种启动模式 – 热爱改变生活
我的GitHub GitHub |     登录
  • If you can't fly, then run; if you can't run, then walk; if you can't walk, then crawl
  • but whatever you do, you have to keep moving forward。
  • “你骗得了我有什么用,这是你自己的人生”
  • 曾有伤心之地,入梦如听 此歌

Activity 深入——四种启动模式

源码分析 sinvader 7877℃ 0评论

[隐藏]

使用 manifest 文件

当在 manifest 文件中声明 Activity 之后,你可以通过 Activity 节点下面的 launchMode 属性去具体指定这个 Activity 是以什么样的方式去与任务连接。
launchMode 属性指定了在任务中,这个 Activity 要以什么样的方式去启动。有四种不同的启动方式可以给 launchMode 去使用。

1.standard 模式

原文:”standard” (the default mode)
Default. The system creates a new instance of the activity in the task from which it was started and routes the intent to it. The activity can be instantiated multiple times, each instance can belong to different tasks, and one task can have multiple instances.

译文:默认的模式。系统在任务中对这个已经运行的 Activity 新建一个实例并且为它指定一个 intent。这个 Activity 可以被多次实例化,每个实例可以属于不同的任务,但是一个任务可以包括多个实例。

2.singleTop 模式

原文:”singleTop”
If an instance of the activity already exists at the top of the current task, the system routes the intent to that instance through a call to its onNewIntent() method, rather than creating a new instance of the activity. The activity can be instantiated multiple times, each instance can belong to different tasks, and one task can have multiple instances (but only if the activity at the top of the back stack is not an existing instance of the activity).

译文:如果要创建的 Activity 实例已经在当前的 task 中存在了,并且位于最顶端,系统将会调用这个实例的 onNewIntent 方法而不是去给这个 activity 创建一个新的实例。这个 activity 可以被实例化多次,每个实例都可以属于不同的 task,并且一个 task 也可以含有多个实例。(但是 activity 本身就存在实例且本来就在 back stack 的顶端的时候除外)

原文:For example, suppose a task’s back stack consists of root activity A with activities B, C, and D on top (the stack is A-B-C-D; D is on top). An intent arrives for an activity of type D. If D has the default “standard” launch mode, a new instance of the class is launched and the stack becomes A-B-C-D-D. However, if D’s launch mode is “singleTop”, the existing instance of D receives the intent through onNewIntent(), because it’s at the top of the stack—the stack remains A-B-C-D. However, if an intent arrives for an activity of type B, then a new instance of B is added to the stack, even if its launch mode is “singleTop”.

译文:举例,假设一个 task 的 back stack 中包含 A、B、C、D 四个 activity,且 A 为根 activity,D 在最上面(也就是在栈中,activity 的顺序从下到上为 ABCD【注:栈是先进后出,类似 汉诺塔】). 这时一个要打开 D 的 intent 来了。如果 D 的 launchMode 是”standard” 的话,一个 D 的新的实例将会被创建,并且在栈中,activity 的顺序从下到上将变成 A-B-C-D-D。如果 D 的 launchMode 是”singleTop” 的话,已经存在的 D 的实例将会调用 onNewIntent 方法来将这个 intent 送达,应为它本来就在栈的最上方——结果是栈中从下到上为 A-B-C-D。如果一个要打开 B Activity 的 intent 来了,一个 B 的新的实例将会被添加到栈中。

原文:Note: When a new instance of an activity is created, the user can press the Back button to return to the previous activity.
But when an existing instance of an activity handles a new intent, the user cannot press the Back button to return to the state of the activity before the new intent arrived in onNewIntent().

译文:注意:当一个 activity 的时候被建立,用户可以按 back 键返回到上一个 activity。
但是当一个已经存在的 activity 处理一个新 intent 时,用户不可能按 back 键回到 intent 到达 activity 的 onNewIntent() 之前的状态。


我写的一个测试代码:
activity 顺序是 (1:)A-B-C-D-B-C-D… 或者为 (2):A-B-C-D-D-D 两种,其中 B-D 的 launchMode 设置为了”singleTop”。
下面是两种顺序的栈中的结果

(1):A-B-C-D-B-C-D...
  Running activities (most recent first):
    TaskRecord{42dd84b8 #125 A cn.sumile.activitylaunchmode U 0}
      Run #8: ActivityRecord{43051f68 u0 cn.sumile.activitylaunchmode/.ThreeActivity}
      Run #7: ActivityRecord{42c265d0 u0 cn.sumile.activitylaunchmode/.TwoActivity}
      Run #6: ActivityRecord{4262fb80 u0 cn.sumile.activitylaunchmode/.oneActivity}
      Run #5: ActivityRecord{425efa20 u0 cn.sumile.activitylaunchmode/.ThreeActivity}
      Run #4: ActivityRecord{42605898 u0 cn.sumile.activitylaunchmode/.TwoActivity}
      Run #3: ActivityRecord{425f35c8 u0 cn.sumile.activitylaunchmode/.oneActivity}
      Run #2: ActivityRecord{425ee270 u0 cn.sumile.activitylaunchmode/.MainActivity}
(2):A-B-C-D-D-D
  Running activities (most recent first):
    TaskRecord{42c0a590 #126 A cn.sumile.activitylaunchmode U 0}
      Run #5: ActivityRecord{4262f5c0 u0 cn.sumile.activitylaunchmode/.ThreeActivity}
      Run #4: ActivityRecord{42605898 u0 cn.sumile.activitylaunchmode/.TwoActivity}
      Run #3: ActivityRecord{425ee270 u0 cn.sumile.activitylaunchmode/.oneActivity}
      Run #2: ActivityRecord{4289c370 u0 cn.sumile.activitylaunchmode/.MainActivity}

从上面我们可以看到,如果 activity 的启动模式为 singletop,当这个 activity 是在栈的最上方(当前显示状态下),那么会调用 onNewIntent 方法,如果不是,会新创建一个实例然后把这个实例放到最上方。

3.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.

译文:系统创建一个新的任务,并且将这个 activity 作为这个新的 task 的最底层 activity。如果这个 activity 的实例已经在另一个 task 中运行,系统会将这个 intent 发送到这个已存在的实例并调用它的 onNewIntent 方法,而不是创建一个新的实例。在同一时间,只能存在一个此 activity 的实例。

原文:Note: Although the activity starts in a new task, the Back button still returns the user to the previous activity.

虽然这个 activity 开启了一个新的 task,但是用户点击 back 键仍然会返回到上一个 activity.

额。。。你信了么?

我没信,于是我做了个实验。(使用命令行,在 adb.exe 所在位置执行 adb shell dumpsys activity)

<activity 
     android:name="cn.sumile.activitylaunchmode.SecondActivity"
     android:launchMode="singleTask" >
</activity>
<activity 
     android:name="cn.sumile.activitylaunchmode.ThirdActivity"
     android:launchMode="singleTask" >
</activity>

上面是两个 activity,并且我把他们的 launchMode 都设为了 singleTask;然后运行看看结果是什么。

  Running activities (most recent first):
    TaskRecord{42fc8210 #129 A cn.sumile.activitylaunchmode U 0}
      Run #3: ActivityRecord{425f1ce0 u0 cn.sumile.activitylaunchmode/.ThirdActivity}
      Run #2: ActivityRecord{425ee270 u0 cn.sumile.activitylaunchmode/.MainActivity}
或是:
  Running activities (most recent first):
    TaskRecord{426167b8 #130 A cn.sumile.activitylaunchmode U 0}
      Run #3: ActivityRecord{425f35c8 u0 cn.sumile.activitylaunchmode/.SecondActivity}
      Run #2: ActivityRecord{425f1b90 u0 cn.sumile.activitylaunchmode/.MainActivity}

尼玛,坑爹呢??!!
泡沫破灭之后,开始各种谷百,拜读到一篇: 解开 Android 应用程序组件 Activity 的”singleTask” 之谜

看完之后我们知道了,需要在 activity 节点下添加一句这个代码:

android:taskAffinity="cn.sumile.android"//内容随意

这次的结果是:

  Running activities (most recent first):
    TaskRecord{42fb1500 #133 A cn.sumile.android U 0}
      Run #3: ActivityRecord{425f35c8 u0 cn.sumile.activitylaunchmode/.SecondActivity}
    TaskRecord{42ebf230 #132 A cn.sumile.activitylaunchmode U 0}
      Run #2: ActivityRecord{425ee270 u0 cn.sumile.activitylaunchmode/.MainActivity}

Mission completed~

4.singleInstance 模式

原文:”singleInstance”.
Same as “singleTask”, except that the system doesn’t launch any other activities into the task holding the instance. The activity is always the single and only member of its task; any activities started by this one open in a separate task.

如果 singleTask 一样,除了系统之外不启动任何 activity 到持有其他实例的 task 中。activity 总是单一的并且是它的 task 的唯一成员,其他任何通过它启动的 activity 总是在不同的 task 中。

原文:As another example, the Android Browser application declares that the web browser activity should always open in its own task—by specifying the singleTask launch mode in the element. This means that if your application issues an intent to open the Android Browser, its activity is not placed in the same task as your application. Instead, either a new task starts for the Browser or, if the Browser already has a task running in the background, that task is brought forward to handle the new intent.

译文:另一个例子是,Android 的浏览器程序声明,它的 activity 应该在它自己的 task 中启动——通过制定它 activity 节点下的 launchMode 属性。这意味着如果你的程序发出了一个打开 Android 浏览器的 intent,它的 activity 和你的程序运行在不同的 task 中。相反,任何一个新的 task 中启动 Browser,或者这个浏览器已经在后台 task 中运行了,这个 task 将会被放到前台来处理这个 intent。

原文:Regardless of whether an activity starts in a new task or in the same task as the activity that started it, the Back button always takes the user to the previous activity. However, if you start an activity that specifies the singleTask launch mode, then if an instance of that activity exists in a background task, that whole task is brought to the foreground. At this point, the back stack now includes all activities from the task brought forward, at the top of the stack. Figure 4 illustrates this type of scenario.

译文:不管一个 activity 是运行在一个新的 task 或者运行在与启动它的 activity 相同的 task 中,back 键总是把用户带到前面的 activity。如果你开启了一个指定 launchMode 为 singleTask 的 activity,那么如果这个 activity 的实例已经后台 task 中存在了,包含这个 activity 的整个 task 将会被带到前台。这时候 back stack 中包含了这个被带到前台的 task 中的全部 activity,在 stack 的最顶部。Figure 4 说明了这种情况:
diagram_backstack_singletask_multiactivity
慕课网 singleInstance 讲解


本篇测试代码下载

¥ 有帮助么?打赏一下~

转载请注明:热爱改变生活.cn » Activity 深入——四种启动模式


本博客只要没有注明“转”,那么均为原创。 转载请注明链接:sumile.cn » Activity 深入——四种启动模式

喜欢 (1)
发表我的评论
取消评论
表情

如需邮件形式接收回复,请注册登录

Hi,你需要填写昵称和邮箱~

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(3)个小伙伴在吐槽
  1. 好文章
    不锈钢网2015-07-17 01:11 回复
  2. 这个目录是怎么实现的?
    云南德信行2015-07-09 11:31 回复
    • 你是指最上面的那个目录么?有个插件,叫 Content Index
      sinvader2015-07-09 12:58 回复