了解launchMode Android活动:标准,singleTop,singleTask和singleInstance

本文的翻译是特别为从事Android开发的高级学生准备的




活动是Android(最流行的移动操作系统,具有精心设计的内存管理架构,可以完美实现多任务)中最引人注目的概念之一。

一种或另一种方式是,随着在屏幕上启动“活动”,并非一切都那么简单。它的运行方式也很重要。这个主题有很多细微差别。真正重要的功能之一是launchMode,我们将在本文中进行讨论。

每个活动的创建都是为了实现不同的目标。其中一些被设计为与每个Intent分别工作,例如,为在邮件客户端中编写电子邮件而发送的活动。而另一些则设计为单例工作,例如活动邮箱。

这就是为什么指出您是需要创建一个新的Activity还是使用一个现有的Activity如此重要的原因,否则会导致不良的UX或崩溃。感谢Android内核开发人员,使用为此专门设计的launchMode可以轻松做到这一点。

LaunchMode定义


从本质上讲,我们可以定义launchMode直接作为标记属性<activity>AndroidManifest.xml

<activity
    android:name=".SingleTaskActivity"
    android:label="singleTask launchMode"
    android:launchMode="singleTask">

有4种可用的launchMode。让我们一次看看他们。

standard

这是默认模式。

设置为此模式的活动的行为将始终创建一个新的活动,以与每个发送的Intent分开工作。实际上,如果发送了10个意图来撰写电子邮件,则必须启动10个活动才能分别为每个意图提供服务。结果,可以在设备上启动无限数量的此类活动。

棒棒糖Android之前的行为

这种活动将在发送Intent的同一任务中创建并放置在堆栈的顶部。



下图显示了当我们与标准活动共享图像时会发生什么。尽管它们来自不同的应用程序,但是它将被堆叠在与上述相同的任务中。



这就是您将在任务管理器中看到的内容。 (这似乎有些奇怪)



如果我们将应用程序切换到另一个任务,然后再切换回Gallery,我们仍然会看到标准的launchMode放置在Gallery任务的顶部。因此,如果需要在图库中做某事,则必须首先在此附加活动中完成工作。

Android Lollipop上的行为

如果这些活动与同一应用程序相关,则其行为将与Lollipop之前的实现中的行为相同-放在任务顶部的堆栈中。



但是,如果Intent是从另一个应用程序发送的,则将创建一个新任务,并将新创建的Activity放置为根,如下所示。



这就是您将在任务管理器中看到的内容。



这是因为任务管理系统已在Lollipop中进行了修改-它变得更加完善和易于理解。在Lollipop中,您可以直接切换回Gallery,因为它是另一项任务。您可以发送另一个Intent,将创建一个新任务,该任务将以与上一个相同的方式服务于Intent。



这种活动的一个示例是撰写电子邮件活动社交网络的状态发布活动。(社交网络上的状态更新)。如果您有一个单独处理每个Intent的Activity,那么您正在考虑标准Activity

单顶


下一个模式是singleTop它的行为与standard几乎相同,这意味着您可以根据需要创建任意数量的singleTop Activity实例。唯一的区别是,如果在调用任务的堆栈顶部已经有一个具有相同类型的Activity实例,则不会创建新的Activity,而是将Intent通过该方法发送到现有的Activity实例onNewIntent()



在singleTop模式下,必须考虑在中处理传入的Intent onCreate()onNewIntent()以便它在所有情况下均有效。

搜索功能是使用此模式的一个示例。让我们考虑创建一个搜索框,该搜索框将您定向到SearchActivity以查看搜索结果。为了获得更好的用户体验,我们通常总是将搜索框放在搜索结果页面上,以允许用户执行下一个搜索而无需返回。

现在想象一下,如果我们总是启动一个新的SearchActivity来提供一个新的搜索结果,那么对于10次搜索迭代,我们将获得10个新的Activity。返回是非常奇怪的,因为您必须单击10次以浏览所有搜索结果才能返回到根活动。

相反,如果SearchActivity已经在堆栈的顶部,则最好将Intent发送到现有的Activity实例,并让其更新搜索结果。现在,堆栈顶部只有一个SearchActivity,您只需单击一次后退按钮即可返回上一个活动。这更有意义。

在任何情况下,singleTop都与调用者在同一任务中工作。如果您希望将Intent发送到其他任何任务之上的现有Activity,那么我应该说它不再有效,这会让您感到失望。如果将Intent从其他应用程序发送到singleTop Activity,则新的Activity将以与标准artingMode(棒棒糖之前:放置在调用任务的顶部,棒棒糖:将创建一个新任务)

singleTask


此模式与standart和singleTop非常不同。具有singleTask launchMode的活动仅在系统中具有一个实例(ala singleton)。如果系统中已经存在一个Activity实例,则保存该实例的整个任务将上移,并且Intent将通过method提供onNewIntent()。否则,将创建一个新的活动,并将其放置在相应的任务中。

在一个应用程序中工作

如果系统中没有singleTask Activity实例,则将创建一个新实例,并将其简单地放在同一任务的堆栈中。



但是,如果存在,位于该singleTask活动上方的所有活动将被自动残酷地销毁(生命周期已完成),以便在堆栈顶部显示所需的活动。同时,Intent将通过一种很棒的方法发送到singleTask活动onNewIntent()



从用户体验的角度来看,这没有任何意义,但是它是通过这种方式设计的。

您会注意到文档中提到的一个细微差别

系统创建一个新任务,并在新任务的根目录处实例化一个活动实例。

但是在实践中,这似乎不像所描述的那样起作用。从命令的结果可以看出,SingleTask Activity仍然位于任务的Activity堆栈的顶部dumpsys activity



sk id #239
  TaskRecord{428efe30 #239 A=com.thecheesefactory.lab.launchmode U=0 sz=2}
  Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.thecheesefactory.lab.launchmode/.StandardActivity }
    Hist #1: ActivityRecord{429a88d0 u0 com.thecheesefactory.lab.launchmode/.SingleTaskActivity t239}
      Intent { cmp=com.thecheesefactory.lab.launchmode/.SingleTaskActivity }
      ProcessRecord{42243130 18965:com.thecheesefactory.lab.launchmode/u0a123}
    Hist #0: ActivityRecord{425fec98 u0 com.thecheesefactory.lab.launchmode/.StandardActivity t239}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.thecheesefactory.lab.launchmode/.StandardActivity }
      ProcessRecord{42243130 18965:com.thecheesefactory.lab.launchmode/u0a123}

如果您希望singleTask活动按照文档中的描述进行操作:创建一个新任务,并将Activity作为根活动。您需要taskAffinity按以下方式为singleTask活动定义一个属性

<activity
    android:name=".SingleTaskActivity"
    android:label="singleTask launchMode"
    android:launchMode="singleTask"
    android:taskAffinity="">

这就是我们尝试运行时的结果SingleTaskActivity





您的任务是taskAffinity根据活动的期望行为来决定是否使用

与另一个应用程序进行交互

一旦从另一个应用程序发送了Intent,并且系统中没有创建Activity的实例,则将创建一个新任务,并将新的Activity放置为根Activity。





如果没有任务将成为调用singleTask活动的所有者,则会显示一个新的活动。



如果任务中存在一个Activity的实例,则整个任务将上移,对于位于单个Task Activity上方的每个Activity,生命周期将完成。如果按下后退按钮,则用户必须先经过堆栈上的“活动”,然后才能返回到调用任务。



使用此模式的示例是任何入口点活动,例如,电子邮件客户端的收件箱页面或社交网络时间轴。这些活动不承担多个实例,因此singleTask将完美地完成其工作。在任何情况下,您都应该明智地使用此模式,因为在这种模式下,活动可能会被破坏而无需用户确认,如上所述。

单实例


此模式与singleTask非常相似,在singleTask上,系统上只能存在一个Activity实例。区别在于,具有此Activity的任务只能具有一个Activity-一个具有singleInstance属性的任务。如果从此类活动中调用了另一个活动,则会自动创建一个新任务来适应该新活动。同样,如果调用singleInstance Activity,则将创建一个新任务来托管此Activity。

无论如何,结果都是很奇怪的。从提供的信息dumpsys,很明显,系统中有两个任务,但是任务管理器中只有一个任务出现,具体取决于哪个任务位于顶部。结果,尽管有任务仍在后台运行,但是我们无法将其切换回前台。这根本没有意义。

这是在堆栈上已经存在活动时调用singleInstance活动的情况。



这就是我们在任务管理器中看到的内容。



由于此任务只能有一个活动,因此我们不能再切换回任务1。唯一的方法是从启动器重新启动应用程序,但是结果singleInstance任务将隐藏在后台。

无论如何,有一些解决此问题的方法。与singleTask活动一样,只需将属性分配taskAffinity给singleInstance活动,从而允许任务管理器中存在多个任务。

<activity
    android:name=".SingleInstanceActivity"
    android:label="singleInstance launchMode"
    android:launchMode="singleInstance"
    android:taskAffinity="">

现在,图片变得更有意义了。



此模式很少使用。一些实际的用例是一个活动启动器或一个应用程序,您可以100%确保只有一个活动。无论如何,除非紧急情况,我建议您不要使用此模式。

意图标志


除了AndroidManifest.xml启动模式直接设置为之外,我们还可以使用称为Intent标志的工具来调整行为,例如:

Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

将以StandardActivity条件singleTop launchMode启动。

您可以使用很多标志。您可以在此处找到有关此信息的更多信息

希望您觉得这篇文章对您有帮助=)

了解有关该课程的更多信息

All Articles