FLAG_ACTIVITY_RESET_TASK_IF_NEEDED和FLAG_ACTIVITY_CLEAR_TOP之间有什么区别? FLAG_ACTIVITY_SINGLE_TOP?

时间:2015-03-28 18:57:44

标签: android android-intent

我正在(最后)为我的书写任务章节,我遇到了一些挥之不去的谜题。

作为主屏幕启动器的内容在启动请求的启动器活动时似乎使用了FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_RESET_TASK_IF_NEEDED的组合:

Intent i=new Intent(Intent.ACTION_MAIN);

i.addCategory(Intent.CATEGORY_LAUNCHER);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
            Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
i.setComponent(name);

startActivity(i);  

The documentation for FLAG_ACTIVITY_RESET_TASK_IF_NEEDED有:

  

如果设置,并且此活动要么在新任务中启动,要么将现有任务置于顶部,那么它将作为任务的前门启动。这将导致应用任务所需的任何关联性,以使该任务处于适当的状态(将活动移入或移出),或者仅在需要时将该任务重置为其初始状态。

那不是特别清楚。

特别是,似乎使用FLAG_ACTIVITY_CLEAR_TOPFLAG_ACTIVITY_SINGLE_TOP的组合可以看到相同的效果。引用FLAG_ACTIVITY_CLEAR_TOP的文档:

  

如果已设置,并且正在启动的活动已在当前任务中运行,则不会启动该活动的新实例,而是将关闭其上的所有其他活动,并将此Intent传递给(现在在最前面)作为新意图的旧活动...

     

当前运行的[所需活动]实例将在其onNewIntent()方法中接收您从此处开始的新意图,或者自己完成并使用新意图重新启动。如果它已宣布其启动模式为"多个" (默认值)并且您没有在同一意图中设置FLAG_ACTIVITY_SINGLE_TOP,然后它将被完成并重新创建;对于所有其他启动模式或者如果设置了FLAG_ACTIVITY_SINGLE_TOP,则此Intent将被传递到当前实例的onNewIntent()。

FLAG_ACTIVITY_CLEAR_TOP文档是有道理的,至少对我而言。

那么,FLAG_ACTIVITY_RESET_TASK_IF_NEEDED做什么与FLAG_ACTIVITY_CLEAR_TOPFLAG_ACTIVITY_SINGLE_TOP的组合不同?


如果您可以解释FLAG_ACTIVITY_CLEAR_TASK与上述其他两个选项中的任何一个不同的话,可以给予奖励积分。

  

如果在传递给Context.startActivity()的Intent中设置,则此标志将导致在活动开始之前清除与活动关联的任何现有任务。也就是说,活动成为否则为空任务的新根,并且任何旧活动都已完成。这只能与FLAG_ACTIVITY_NEW_TASK一起使用。

这与FLAG_ACTIVITY_CLEAR_TOP |之间有一个明显的区别FLAG_ACTIVITY_SINGLE_TOP需要FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_NEW_TASK。但是,除此之外,看起来净效果是相同的,并且匹配FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

3 个答案:

答案 0 :(得分:40)

我查看了ActivityManager的源代码。标志Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED确实做了Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP不做的一些魔术:它触发任务重新定位

这是一个(虽然很蹩脚)的例子:

在App A中,我们有根活动RootA,我们还有另一个活动ReparentableA

<application
        android:label="@string/app_name">
    <activity android:name=".RootA">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
    <activity android:name=".ReparentableA"
            android:allowTaskReparenting="true"/>
</application>

App A的包名为“com.app.a”,因此其组件的默认taskAffinity为“com.app.a”。

在App B中,我们有根活动RootB

<application
        android:label="@string/app_name">
    <activity android:name="RootB">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
</application>

App B的包名为“com.app.b”,因此其组件的默认taskAffinity为“com.app.b”。

现在我们从HOME屏幕启动App B.这将启动一个新任务,并创建一个活动RootB的新实例作为该任务中的根Activity。活动RootB现在以标准方式启动活动ReparentableA,没有任何特殊标记。在当前任务中创建ReparentableA的实例并置于RootB之上。

按HOME。

现在我们从HOME屏幕启动App A.这将启动一个新任务,并创建一个活动RootA的新实例作为该任务中的根Activity。注意:当Android启动“启动器”意图时,它会自动设置标记Intent.FLAG_ACTIVITY_NEW_TASKIntent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED。因此,启动RootA现在会触发任务重新创建。 Android会查看是否在任何其他任务中有任何与此新任务具有亲缘关系的活动(并且是可重新定位的)。它在App B任务中找到ReparentableA(与RootA具有相同的任务关联性)并将其移动到新的App A任务。启动应用A时,我们看不到RootA,我们实际上看到ReparentableA,因为它已移至新任务的顶部。

如果我们返回App B,我们可以看到ReparentableA已从任务堆中消失,该任务现在只包含一个活动:RootB


关于使用Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP

的说明

使用这些标志“重置任务”时要记住的重要事项是只有在任务根中已存在目标活动的实例时才会起作用。如果您的根活动已完成,则无法通过使用Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP启动根活动来清除您的任务。 Android将只创建一个目标(root)Activity的新实例,并将置于任务中的现有活动之上,这可能完全不是您想要的。


Intent.FLAG_ACTIVITY_CLEAR_TASKIntent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP之间的差异:

如上所述,只有在任务中已存在目标活动的实例时,才使用CLEAR_TOP | SINGLE_TOP。但是,CLEAR_TASK会从任务中删除所有活动,无论任务中是否存在目标活动的实例。此外,使用CLEAR_TASK可确保目标Activity成为任务的根Activity,而无需在清除任务之前知道Activity是哪个Activity。


Intent.FLAG_ACTIVITY_CLEAR_TASKIntent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED之间的差异:

如上所述,使用CLEAR_TASK始终从任务中删除所有活动并启动目标活动的新实例。相反,RESET_TASK_IF_NEEDED只会在某些情况下重置任务(“IF_NEEDED”部分)。如果Android是以下任务,则任务仅“重置”:

  • 创建新任务(在这种情况下,“重置”功能涉及上面解释的任务重新定义),或
  • 如果Android将后台任务带到前台(在这种情况下,任务仅清除使用Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET启动的任何活动以及这些活动之上的任何活动)。注意:在这种情况下,根活动永远不会被清除。

重要提示:在进行测试时,请注意Android在从HOME屏幕(或可用应用程序列表)启动应用程序时以及选择任务时的行为方式有所不同来自最近的任务清单。

在第一种情况下(通过从可用应用程序列表中选择应用程序或从HOME屏幕上的快捷方式启动应用程序),将创建一个带有Intent的启动器Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED。无论应用程序是否已在运行,都会使用此选项。 Intent已启动,然后ActivityManager会确定要执行的操作。

在第二种情况下(从最近任务列表中选择一个任务),如果任务仍然存在,则只是将其置于前面。如果使用最近的任务列表将任务放在前面,则不执行任务“重置”。对我来说这是如何管理的并不是很明显,我也没有机会查看源代码以找出原因。


我希望这能回答你的问题。期待您的反馈和测试结果。

答案 1 :(得分:2)

我可能会在这里弄错,但在我的理解中FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED会分析所有任务,并确保只有一个启动器活动的任务正在运行。

FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP将仅检查当前任务,因此您最终可能会同时运行2个启动器实例(如果第一个启动实例是作为单独的任务创建的)。

答案 2 :(得分:0)

1)FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

如果某个任务处于待处理状态,则会破坏该进程并启动您请求的活动

2)FLAG_ACTIVITY_CLEAR_TOP

如果此活动的任何先前意图正在运行,则此方法将提供活动的正在运行的实例,关闭所有其他活动并将使用上一个实例启动活动。

3)FLAG_ACTIVITY_SINGLE_TOP

如果最近已启动此活动并保存实例,则不会启动此活动。