Android“单顶”启动模式和onNewIntent方法

Posted

技术标签:

【中文标题】Android“单顶”启动模式和onNewIntent方法【英文标题】:Android "single top" launch mode and onNewIntent method 【发布时间】:2010-12-15 06:28:31 【问题描述】:

我在 android 文档中读到,通过将 Activity 的 launchMode 属性设置为 singleTop 或通过将 FLAG_ACTIVITY_SINGLE_TOP 标志添加到我的 Intent,调用 startActivity(intent) 将重用单个 Activity 实例并在 @987654324 中为我提供 Intent @ 打回来。我做了这两件事,onNewIntent 永远不会触发,onCreate 每次都会触发。文档还说this.getIntent() 返回第一次创建时第一次传递给 Activity 的意图。在onCreate 我打电话给getIntent 并且我每次都得到一个新的(我在另一个活动中创建意图对象并添加一个额外的......这个额外的每次都应该是相同的,如果它向我返回了相同的意图对象)。所有这一切让我相信我的活动不像“单顶”,我不明白为什么。

为了添加一些背景以防我只是错过了一个必需的步骤,这是我在清单中的 Activity 声明以及我用来启动该 Activity 的代码。 Activity 本身在这方面没有做任何值得一提的事情:

在 AndroidManifest.xml 中:

    <activity
        android:name=".ArtistActivity"
        android:label="Artist"
        android:launchMode="singleTop">
    </activity>     

在我的通话活动中:

        Intent i = new Intent();
        i.putExtra(EXTRA_KEY_ARTIST, id);
        i.setClass(this, ArtistActivity.class);
        i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(i);

【问题讨论】:

查看此幻灯片。它很好地解释了launchMode:slideshare.net/RanNachmany/… 【参考方案1】:

您是否检查过onDestroy() 是否也被调用过?这可能就是为什么每次都调用onCreate() 而不是onNewIntent() 的原因,onNewIntent() 只有在活动已经存在时才会被调用。

例如,如果您通过 BACK 按钮离开您的活动,则默认情况下它会被销毁。但是,如果您在活动堆栈上向上进入其他活动并从那里再次调用您的ArtistActivity.class,它将跳过onCreate()并直接转到onNewIntent(),因为该活动已经创建并且因为您将其定义为@ 987654327@Android 不会创建它的新实例,而是取一个已经存在的实例。

我做什么来看看发生了什么我为每个活动的所有不同状态实现了虚拟函数,所以我总是现在发生了什么:

@Override
public void onDestroy() 
    Log.i(TAG, "onDestroy()");
    super.onDestroy();

onRestart()onStart()onResume()onPause()onDestroy() 相同

如果上述(BACK 按钮)不是您的问题,那么实现这些虚拟对象至少可以帮助您更好地调试它。

【讨论】:

这很可能是正在发生的事情。我创建了类似“登陆页面”活动作为入口点。从着陆点,您选择一位艺术家并转到 ArtistActivity。用户使用后退按钮返回主活动并再次选择。我的印象是 Activity 在第一次使用后会挂起,并且我会通过不重新实例化它来节省性能。我应该担心这里的性能,还是这种模式适合简单的活动? 嗨,我和 OP 有同样的问题,但在我的情况下,onDestroy 从来没有被调用过——我只是得到了全新的活动实例:-s。还有其他想法吗? android:launchMode="singleTask" - 在我的情况下,有问题的活动是从其主要任务之外开始的 @kellogs 很棒的提示。我正在开发一个基于 NFC 的应用程序,每次用标签触摸手机时,我的活动的一个新实例就会启动。 Jump-Back-Hierarchy 一团糟。 launchmode="singleTask" 有很大帮助,运行时环境可以防止多次实例化同一个活动,这对我帮助很大!谢谢。 我看到 ondestory() 没有被调用。每次只调用 onStop() 。其实更有可能直接进入onResume(),既不是onCreate(),也不是onNewintent();【参考方案2】:

接受的答案并不完全正确。如果之前调用了 onDestroy(),那么是的,总是会调用 onCreate()。但是,这种说法是错误的: “如果您在活动堆栈上更高的位置进入其他活动,并从那里再次调用您的 ArtistActivity.class,它将跳过 onCreate() 并直接转到 onNewIntent()”

http://developer.android.com/guide/components/tasks-and-back-stack.html 的“singleTop”部分清楚地解释了它是如何工作的(注意下面的粗体文字;我也通过自己的调试证明了这一点):

“例如,假设一个任务的后台堆栈由根活动 A 和顶部的活动 B、C 和 D 组成(堆栈是 ABCD;D 在顶部)。一个意图到达D 类型的活动。如果 D 具有默认的“标准”启动模式,则启动该类的新实例并且堆栈变为 ABCDD。但是,如果 D 的启动模式为“singleTop”,则 D 的现有实例会收到意图通过 onNewIntent(),因为它在栈顶——栈仍然是 ABCD。但是,如果一个意图到达 B 类型的活动,那么 B 的一个新实例将被添加到栈中,即使它的启动模式是“singleTop”。”

换句话说,通过 SINGLE_TOP 启动一个活动只会重用现有的活动,如果它已经在堆栈的顶部。如果同一任务中的另一个活动位于顶部(例如,正在执行 startActivity(SINGLE_TOP) 的活动),它将不起作用;将创建一个新实例。

这里有两种方法可以解决此问题,以便您获得所需的 SINGLE_TOP 行为——其一般目的是重用现有活动,而不是创建新活动...

第一种方式(如接受的评论部分所述 答案):您可以将“singleTask”的launchMode添加到您的活动中。这将强制 onNewIntent() 因为 singleTask 意味着在给定任务中只能有一个特定活动的实例。这是一个有点老套的解决方案,因为如果您的应用在特定情况下需要该活动的多个实例(就像我为我的项目所做的那样),那么您就完蛋了。

第二种方式(更好): 使用 FLAG_ACTIVITY_REORDER_TO_FRONT 代替 FLAG_ACTIVITY_SINGLE_TOP。这将通过将现有活动实例移动到堆栈顶部来重用它(onNewIntent() 将按预期调用)。

FLAG_ACTIVITY_SINGLE_TOP 的主要目的是防止创建一个 Activity 的多个实例。例如,当该活动可以通过来自应用程序主任务之外的意图启动时。对于我的应用程序中的活动之间的内部切换,我发现 FLAG_ACTIVITY_REORDER_TO_FRONT 通常是我想要的。

【讨论】:

谢谢。实际上,接受的答案解释对于“singleTask”行为是正确的,但不适用于向上导航可以创建一个活动的多个实例的“singleTop”。 一件事.. 在第二种方式中,使用 FLAG_ACTIVITY_REORDER_TO_FRONT 仍然应该与 launchMode "singleTop" 结合对吗?【参考方案3】:

将此标志设置为您的意图:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)

【讨论】:

以上是关于Android“单顶”启动模式和onNewIntent方法的主要内容,如果未能解决你的问题,请参考以下文章

Activity的启动模式和onNewIntent()

Android之Activity的启动模式

Android启动模式以及IntentFilter匹配规则

再来看看应用-onNewIntent

再来看看应用-onNewIntent

Android组件体系之Activity启动模式解析