launchMode
属性在manifest
中的launcher activity
是否被忽略了? 根据android
文档,其默认值为"standard",但如果将其应用于应用程序的主要活动,则对我来说这似乎是不合理的,因为每次启动应用程序时,都会在实例中创建另一个task
。
launchMode
属性在manifest
中的launcher activity
是否被忽略了? 根据android
文档,其默认值为"standard",但如果将其应用于应用程序的主要活动,则对我来说这似乎是不合理的,因为每次启动应用程序时,都会在实例中创建另一个task
。
我自己深入研究了Android源代码,并发现了以下内容。
启动器使用LauncherAppsService
中的startActivityAsUser
方法启动应用程序。该意图是使用以下行构建的:
Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIntent.setComponent(component);
launchIntent.setSourceBounds(sourceBounds);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
根据Android文档,标志FLAG_ACTIVITY_NEW_TASK
的含义是:launchMode
(或默认行为省略该属性),并忽略了此属性。FLAG_ACTIVITY_NEW_TASK
的命名有些具有欺骗性。 - Kevin KrumwiedelaunchMode
,另一个是“当用户从主屏幕选择应用程序图标或从最近任务列表中选择任务时会发生什么”。这些是完全不同的两种情况。
launchMode
每个Activity
都有指定的launchMode
(默认为"standard"
或"multiple"
)。这告诉Android如何启动此Activity
,许多因素可以影响launchMode
的“解释”。它取决于在使用的Intent
中可能已经指定的其他标志。它取决于请求启动Activity
的任务(或者如果从非活动上下文,如Service
或BroadcastReceiver
中请求启动,则取决于是哪个任务)。它还取决于指定任务中是否已经存在Activity
实例等。startActivity()
并包含以下数据的Intent
:
Activity
的包名和类名FLAG_ACTIVITY_NEW_TASK
和FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
。Activity
的launchMode
定义如何,使用这样的Intent
调用startActivity()
都会导致以下行为:Activity
匹配(简单地说,如果应用程序已经在运行),Android将简单地将现有任务带到前台。仅此而已。它不创建任何Activity
实例。它不在任何Activity
上调用onNewIntent()
。除了将现有任务带到前台之外,它什么都不做。这就是为什么,即使您的启动器Activity
指定了launchMode="standard"
,每次单击应用程序图标时Android也不会创建新的实例的原因。Activity
具有任务亲和性的现有任务(简单地说,如果应用程序尚未运行),则Android会创建一个新任务并将Activity
启动到该任务中。由于在将单个Activity
启动到新任务时,无论启动模式如何都没有任何区别,因此launchMode
在这里不起作用。Android始终创建新任务,并始终创建新Activity
的实例作为该任务的根。Activity
实例,并且不会调用onNewIntent()
。如果任务不再运行,则Android创建一个新任务,并将launcher Activity
启动到该任务中。唯一的区别是,如果用户从最近任务列表中选择了任务,则Intent
中还设置了FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
标志。FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
和任务重新分配的非常详细的解释,请参见此答案。launchMode
在许多情况下都不起作用,并且被“外部”意图覆盖,我认为这应该在launchMode
文档中更详细地描述。 - StanActivity
的另一个实例,这并没有任何与launchMode
有关。无论指定什么launchMode
都不会有任何区别。这种行为根本与launchMode
无关。它也与主窗口背景颜色,使用的字体或月相无关。我不明白为什么需要在文档中指定这一点。 - David WasserlaunchMode
是无用或者误导性的。这确实是“关于Activity应该如何启动的指示”,但并不代表它一定会以这种方式被启动。 - StanlaunchMode
是无用或者误导性的。我是在说,还有其他因素可以修改launchMode
所指定的行为。任务亲和性、启动上下文和Intent
标志都可能会影响Android在调用startActivity()
时实际执行的操作。 - David Wasser把开头的活动以外的所有内容都看作是一个抽象实现。将一个活动声明为
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
会使其首先打开。在形成导航活动的意图时,后续活动将被覆盖。这些覆盖表示为意图标志。
意图附加项列表: http://developer.android.com/reference/android/content/Intent.html
标志是您本来应在清单中编写的命令。
<intent-filter>
不会被覆盖。当使用隐式Intent启动活动时,才会使用Intent过滤器。如果您使用显式Intent启动Activity
,则不会使用Intent过滤器。这与抽象、继承和覆盖无关。 - David Wasser你是对的。默认模式是“标准模式”。
根据Android文档
*在“标准模式”下,每次有新的意图要启动一个“标准”活动时,都会创建该类的新实例来响应该意图。每个实例处理一个意图。
*如果父活动具有启动模式“标准”(并且向上意图不包含
FLAG_ACTIVITY_CLEAR_TOP
),则当前活动及其父活动都将从堆栈中弹出,并创建父活动的新实例以接收导航意图。
将Activity的行为设置为标准模式,这意味着每次发送Intent时都会创建一个新的Activity以独立地处理该Intent。例如,如果要发送10个Intent来撰写一封电子邮件,就应该启动10个Activity来分别处理每个Intent。因此,在设备上可能会无限制地启动此类Activity。
Android Lollipop之前的行为
在相同的任务中,标准Activity将被创建并置于堆栈的顶部,与发送Intent的Activity相同。例如,当我们从图库分享图像到标准Activity时,尽管它们来自不同的应用程序,但它们将被堆叠在相同的任务中描述。如果我们切换到另一个应用程序,然后再切换回图库,我们仍将看到标准的launchMode置于Gallery的任务顶部。因此,如果我们需要在Gallery中执行任何操作,我们必须先完成该附加Activity中的工作。
Android Lollipop上的行为
如果活动来自同一应用程序,则其行为与Lollipop之前的版本相同,堆叠在任务的顶部。 但是,如果从不同的应用程序发送意图,则会创建新任务,并将新创建的活动放置为根活动,如下所示。
来源于这里