之间有什么FLAG_ACTIVITY_RESET_TASK_IF_NEEDED和FLAG_ACTIVITY_CLEAR_TOP差异| FLAG_ACTIVITY_SINGLE_TOP?有什么、差异、F

2023-09-05 00:08:12 作者:我爱你不怕万人阻拦@

我在(最终)写在任务的章节我的书的过程中,我遇到了一些挥之不去的难题。

I am in the process of (finally) writing the chapter on tasks for my book, and I am encountering a few lingering puzzles.

对作为主屏幕发射似乎使用了 FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 它们启动时所要求的组合发射活动:

Things that serve as home screen launchers seem to use the combination of FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_RESET_TASK_IF_NEEDED when they launch the requested launcher activity:

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为 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 文件有:

The documentation for FLAG_ACTIVITY_RESET_TASK_IF_NEEDED has:

如果设置,并且该活动是任一被启动在一个新的任务或将顶端现有任务,那么它将被推出作为任务的前门。这将导致需要有在适当的状态下,任务的任何亲和力的应用(或者移动活动或从它),或简单地复位该任务到其初始状态,如果需要的。

If set, and this activity is either being started in a new task or bringing to the top an existing task, then it will be launched as the front door of the task. This will result in the application of any affinities needed to have that task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed.

这不是特别清楚。

在特定的,它似乎是相同的效果会使用 FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_SINGLE_TOP 的组合可以看出。引用该文档的 FLAG_ACTIVITY_CLEAR_TOP

In particular, it would seem that the same effects would be seen using a combination of FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP. Quoting the docs for FLAG_ACTIVITY_CLEAR_TOP:

如果设置,并且活动被启动已经在当前任务中运行,然后代替启动该活动的一个新实例,所有的在其上的其他活动将被关闭,此意图将被传递到的(现在的顶部)老年活动作为一个新的意图...

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent...

的〔所需活性]将要么接收新的意图要启动这里在其onNewIntent()方法,或者是本身完成,重新开始与新的意图当前正在运行的实例。如果它已经宣布启动模式是多(默认值),尚未设置FLAG_ACTIVITY_SINGLE_TOP的目的相同,那么将完成并重新创建;对于所有其它发射模式,或者如果FLAG_ACTIVITY_SINGLE_TOP被设置,那么这种意图将传送给当前实例的onNewIntent()。

The currently running instance of [the desired activity] will either receive the new intent you are starting here in its onNewIntent() method, or be itself finished and restarted with the new intent. If it has declared its launch mode to be "multiple" (the default) and you have not set FLAG_ACTIVITY_SINGLE_TOP in the same intent, then it will be finished and re-created; for all other launch modes or if FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be delivered to the current instance's onNewIntent().

FLAG_ACTIVITY_CLEAR_TOP 文件是有道理的,至少对我来说。

The FLAG_ACTIVITY_CLEAR_TOP documentation makes sense, at least to me.

那么,什么是 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 做的比的组合不同的 FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_SINGLE_TOP

So, what does FLAG_ACTIVITY_RESET_TASK_IF_NEEDED do that is different than the combination of FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP?

奖励积分,如果你能解释一下FLAG_ACTIVITY_CLEAR_TASK这是否是从任一上述其它两种选择的不同

Bonus points if you can explain what FLAG_ACTIVITY_CLEAR_TASK does that is different from either of the other two options described above.

如果在)传递给Context.startActivity(一个Intent设置时,该标志将导致将与该活动相关联的任何现有任务的活动开始前被清除。即,活性变得的人少的任务的新的根,和任何旧的活动完成。这只能在与FLAG_ACTIVITY_NEW_TASK一起使用。

下面不是android四大组件之一的是,Android四大组件之活动

If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with 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

One obvious difference between this and FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP is that FLAG_ACTIVITY_CLEAR_TASK needs FLAG_ACTIVITY_NEW_TASK. But, other than that, it would seem like the net effects are the same, and also match FLAG_ACTIVITY_RESET_TASK_IF_NEEDED.

推荐答案

我看了一下源$ C ​​$ C为 ActivityManager 。标志 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 确实做了一些魔法 Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP 不会做的事:它引发的任务重排根目录

I had a look at the source code for the ActivityManager. The flag Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED does indeed do some magic that Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP does not do: It triggers task reparenting.

下面是一个(虽然蹩脚)例如:

Here's an (albeit lame) example:

在应用程序中的我们有根系活力 RootA 和我们有另一个活动 ReparentableA

In App A we have the root Activity RootA and we have another Activity 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>

应用程序中的有包名com.app.a所以默认 taskAffinity 组件为com.app.a。

App A has the package name "com.app.a" so the default taskAffinity of its components is "com.app.a".

在附录二,我们有根系活力 RootB

In App B we have the root Activity 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>

应用程序B的包名com.app.b所以默认 taskAffinity 组件为com.app.b。

App B has the package name "com.app.b" so the default taskAffinity of its components is "com.app.b".

现在我们从主屏幕发射附录二。这将启动一个新任务,并创建活动 RootB 在该任务的根系活力的新实例。活动 RootB 现推出活动 ReparentableA 以标准的方式,没有任何特殊的标志。实例 ReparentableA 创建并放在 RootB 的顶部,在当前的任务。

Now we launch App B from the HOME screen. This starts a new task and creates a new instance of Activity RootB as the root Activity in that task. Activity RootB now launches Activity ReparentableA in the standard way, without any special flags. An instance of ReparentableA is created and put on top of RootB in the current task.

preSS HOME。

Press HOME.

现在我们启动一个应用程序从HOME画面。这将启动一个新任务,并创建活动 RootA 在该任务的根系活力的新实例。注:Android的推出了发射的意图,它会自动设置标志 Intent.FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 。正因为如此,发动 RootA 现在触发任务重排根目录。机器人查看是否有在具有这个新任务的亲和力(和是reparentable)的任何其他任务的任何活动。它找到 ReparentableA (其中有相同的任务亲和力 RootA )的附录二的任务,并将其移动到新的应用程序的任务。当启动应用程序中的,我们没有看到 RootA ,我们实际看到 ReparentableA ,因为它移动到的顶部新的任务。

Now we launch App A from the HOME screen. This starts a new task and creates a new instance of Activity RootA as the root Activity in that task. NOTE: When Android launches a "launcher" Intent, it automatically sets the flags Intent.FLAG_ACTIVITY_NEW_TASK and Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED. Because of this, launching RootA now triggers task reparenting. Android looks to see if there are any activities in any other tasks that have an affinity for this new task (and are reparentable). It finds ReparentableA (which has the same task affinity as RootA) in the App B task and moves it to the new App A task. When launching App A we do not see RootA, we actually see ReparentableA, as it is moved to the top of the new task.

如果我们回到应用程序B,我们可以看到, ReparentableA 从任务堆栈走了,这个任务现在只包含一个活动的: RootB

If we return to App B, we can see that ReparentableA is gone from the task stack and that task now consists of only one Activity: RootB.

有关使用注意事项 Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP

要记住使用这些标志为重置任务重要的是,它只能如果已经有目标活动的一个实​​例,在任务的根目录。如果你的根永远的活动结束后,你不能用 Intent.FLAG_ACTIVITY_CLEAR_TOP启动根系活力清除任务| Intent.FLAG_ACTIVITY_SINGLE_TOP 。 Android将刚刚创建目标(根)活动的一个新实例,并把它的在现有的活动之上任务,这可能不是在所有你想要的。

The important thing to remember about using these flags to "reset a task" is that it only works if there is already an instance of the target Activity at the root of the task. If your root Activity ever finishes, you cannot clear your task by starting the root Activity with Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP. Android will just create a new instance of the target (root) Activity and put it on top of the existing activities in the task, which is probably not at all what you want.

Intent.FLAG_ACTIVITY_CLEAR_TASK Intent.FLAG_ACTIVITY_CLEAR_TOP差| Intent.FLAG_ACTIVITY_SINGLE_TOP

如上所述,使用 CLEAR_TOP | SINGLE_TOP 只有当已经有在任务目标活动的一个实​​例。 CLEAR_TASK ,但是,删除所有活动的任务,而不管是否有在任务目标活动的一个实​​例。此外,使用 CLEAR_TASK 确保目标的活动变成任务的根系活力,没有你需要知道哪些活动是根系活力您清除任务之前。

As noted above, using CLEAR_TOP | SINGLE_TOP only works if there is already an instance of the target Activity in the task. CLEAR_TASK, however, removes all activities from the task, regardless of whether or not there was an instance of the target Activity in the task. Also, using CLEAR_TASK ensures that the target Activity becomes the root Activity of the task, without you needing to know what Activity was the root Activity before you cleared the task.

区别 Intent.FLAG_ACTIVITY_CLEAR_TASK Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

如上所示,使用 CLEAR_TASK 将总是从任务中删除所有的活动,并启动目标活动的新实例。与此相反, RESET_TASK_IF_NEEDED 仅重置在某些情况下任务(以下简称IF_NEEDED的一部分)。该任务不仅是复位,如果Android是两种:

As indicated above, using CLEAR_TASK will always remove all activities from the task and launch a new instance of the target activity. In contrast, RESET_TASK_IF_NEEDED will only reset the task in certain situations (the "IF_NEEDED" part). The task is only "reset" if Android is either:

创建一个新的任务(在此情况下,复位功能涉及任务重排根目录上面已说明),或 如果Android正在把一个后台任务切换到前台(在这种情况下,任务才会被清除的是,启动了 Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 的活动,而且任何的活动这些活动的顶部)。注:根系活力不会被清零在这种情况下 Creating a new task (in which case the "reset" functionality involves the task reparenting explained above), or If Android is bringing a background task to the foreground (in which case the task is only cleared of any activities that were launched with Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET and any activities that are on top of those activities). NOTE: The root Activity is never cleared in this case.

重要提示::当您正在测试,请注意,在Android的推出从HOME画面的应用程序(或从可用的应用程序列表)时的行为方式的不同,选择的时候任务从最近的任务列表。

IMPORTANT NOTE: When you are testing, please note that there is a difference in the way Android behaves when launching apps from the HOME screen (or from the list of available applications) and when selecting tasks from the recent task list.

在第一种情况下(从可用应用程序的列表,或从一个快捷方式在主屏幕上选择它启动一个应用程序),一个发射意图 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 创建。此不管该应用是否已经运行被使用。该意图启动,然后 ActivityManager 计算出该怎么做。

In the first case (launching an app by selecting it from the list of available applications or from a shortcut on the HOME screen), a launcher Intent with Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED is created. This is used regardless of whether or not the app is already running. The Intent is launched and then the ActivityManager figures out what to do.

在第二种情况下(从选择的最近的任务列表中的任务),如果任务仍然存在,它只是带来的前面。任务重置是不是如果任务只是把使用近期任务列表中的前执行。这不是明显对我来说这是如何管理的,我已经没有机会仔细看看源$ C ​​$ C弄清楚这是为什么。

In the second case (selecting a task from the list of recent tasks), if the task still exists, it is just brought the front. The task "reset" is NOT performed if the task is just brought to the front using the recent task list. It isn't obvious to me how this is managed and I've not had a chance to look through the source code to figure out why that is.

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

I hope this answers your questions. Looking forward to your feedback and test results.