意图 - 如果活动正在运行,请将其放在前面,否则启动一个新活动(来自通知)

Posted

技术标签:

【中文标题】意图 - 如果活动正在运行,请将其放在前面,否则启动一个新活动(来自通知)【英文标题】:Intent - if activity is running, bring it to front, else start a new one (from notification) 【发布时间】:2013-10-03 01:37:52 【问题描述】:

我的应用有通知,显然 - 没有任何标志,每次都会启动一个新的活动,所以我得到多个相同的活动在彼此之上运行,这是错误的。

我想要它做的是将通知待处理意图中指定的活动放在前面,如果它已经在运行,否则启动它。

到目前为止,我拥有的该通知的意图/待定意图是

private static PendingIntent prepareIntent(Context context) 
    Intent intent = new Intent(context, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

奇怪的是,它有时有效,有时无效……我觉得我已经尝试过每一种标志组合。

【问题讨论】:

【参考方案1】:

我认为最好的简单方式是正常启动活动,但在清单中使用singleInstance 属性设置该活动。有了这个,您实际上可以解决您现在遇到的两个问题,方法是始终将活动置于最前面,并让操作系统在不存在活动时自动创建一个新活动,或者将当前存在的活动置于最前面(感谢singleInstance 属性)。

这是将活动声明为单个实例的方式:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleInstance"/>

另外,为了避免在通过 singleInstance 启动时出现断断续续的动画,您可以使用“singleTask”来代替,两者非常相似,但这里根据 Google 的文档解释了不同之处:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleTask"/>

singleInstance 与“singleTask”相同,只是系统 不会在持有该任务的任务中启动任何其他活动 实例。该活动始终是其唯一且唯一的成员 任务。

希望这会有所帮助。

问候!

【讨论】:

它似乎有效,但现在我从 singleIntent MainActivity 启动的所有其他新活动,播放这个奇怪的弧形动画而不是常规的淡入淡出和缩放 如果我每次都启动一个新的活动,但清除它所有其他正在运行的实例,这可能吗? 好吧,我认为您提到的动画与“singleInstance”属性没有任何关系,它所做的只是重用现有实例,也许您正在谈论的动画是一个完全不同的问题... 嗯,我现在正在测试它,它确实如此。如果我删除所有意图标志并在清单中设置 launchMode="singleInstance",那么奇怪的动画就在那里,如果我删除它,它就会恢复正常 是的,根据android文档,“init”动画似乎不再像往常一样存在,因为活动没有被初始化,只是被重用......【参考方案2】:

你可以用这个:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleTask"/>

这将类似于"singleInstance",但它不会有那种奇怪的动画。

【讨论】:

+1,您应该是公认的答案。区别在这里:developer.android.com/guide/topics/manifest/… 澄清一下,如果您在应用程序中有多个活动并且这是父活动,请使用 singleTask,如果您只有一个活动,请使用 singleInstance。 如果像我这样的人在最终访问此站点之前尝试了多种解决方案组合:请确保摆脱您尝试过的其他更改,并确保对正确的活动进行此更改。我花了很长时间才发现如果我没有尝试其他解决方案(例如覆盖 onNewIntent 和设置标志),这个解决方案会起作用 我有一张 Messenger、Activity 对的地图。如果我收到消息,我想显示 Activity 实例。有没有办法做到这一点。例如:HashMap.get(Messenger).bringActivityToFront();我的意思是,活动仍在进行中。如果我打开最近的任务并单击它,它将 onResume();我不能以编程方式 onResume()。 @JaveneCPPMcGowan 这似乎是一个完全不同的问题,我建议您将其发布为自己的问题,不幸的是我真的不知道答案。【参考方案3】:

既然你说你想开始你的活动,如果它还没有开始,也许你不介意重新开始它。我还针对意图测试了大量建议和标志组合,这将始终将您需要的活动带到最前面,尽管它不会保留以前与之关联的任何状态。

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);

仅限 API11+。

【讨论】:

【参考方案4】:

我认为您需要的是singleTop Activity,而不是singleTasksingleInstance

<activity android:name=".MyActivity"
          android:launchMode="singleTop"
          ...the rest... >

the documentation says 完全符合您的需求:

[...] 还可以创建一个“singleTop”活动的新实例来处理 一个新的意图。但是,如果目标任务已经存在 位于其堆栈顶部的活动实例,该实例将 接收新意图(在onNewIntent() 呼叫中);一个新实例是 未创建。在其他情况下——例如,如果现有 “singleTop”活动的实例在目标任务中,但不在 堆栈的顶部,或者如果它在堆栈的顶部,但不在 目标任务——将创建一个新实例并将其推送到堆栈上。

除此之外(不是双关语),我的需求与您完全相同。我测试了所有launchMode 标志以了解它们在实践中的实际行为,结果singleTop 实际上是最好的:没有奇怪的动画,应用程序在最近的应用程序列表中显示一次(不像singleInstance 显示它两次,因为它不允许任何其他 Activity 成为其任务的一部分),并且无论目标 Activity 是否已经存在,都应采取适当的行为。

【讨论】:

周五晚上工作到晚上 10 点,这就是我想要的……悲伤的开发人员生活。 节省了我很多时间!谢谢!【参考方案5】:

我试过了,即使 IDE 抱怨代码,它也能正常工作

Intent notificationIntent = new Intent(THIS_CONTEXT, MainActivity.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    PendingIntent intent = PendingIntent.getActivity(THIS_CONTEXT, 0, notificationIntent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(THIS_CONTEXT)
            .setSmallIcon(R.drawable.cast_ic_notification_0)
            .setContentTitle("Title")
            .setContentText("Content")
            .setContentIntent(intent)
            .setPriority(PRIORITY_HIGH) //private static final PRIORITY_HIGH = 5;
            .setAutoCancel(true)
            /*.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)*/;
    NotificationManager mNotificationManager = (NotificationManager) THIS_CONTEXT.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(0, mBuilder.build());

【讨论】:

Intent.FLAG_ACTIVITY_REORDER_TO_FRONT 不是PendingINtent.getActivity 的有效标志 @rds 你能链接源吗? @LouisCAD 对不起,我无法再访问源代码了 @rds 我不是要源代码,而是要你读到Intent.FLAG_ACTIVITY_REORDER_TO_FRONT 在用作PendingIntent 时不是有效标志的链接。或者,也许您的意思是传递给getActivity 方法是无效的,但可以用作Intent 标志,然后用作PendingIntent【参考方案6】:

我知道它已经过时了,但以上内容都不适合我的应用程序。

在不更改清单和其他配置的情况下,这里是让您的应用回到前面的代码 - 或者在关闭时打开它

Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
notificationIntent.setPackage(null); // The golden row !!!
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

【讨论】:

这才是真正的答案! 不,它不起作用 - 它会在当前活动之上添加一个新活动。 @Tobliug 我想如果您尝试删除标志 FLAG_ACTIVITY_NEW_TASK 会为您工作?【参考方案7】:

这是旧线程,但对于所有仍在寻求答案的人,这是我的解决方案。它纯粹是代码,没有清单设置:

private static PendingIntent prepareIntent(Context context) 
  Intent intent = new Intent(context, MainActivity.class);
  intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);      
  return PendingIntent.getActivity(context, NON_ZERO_REQUEST_CODE, intent, 
    PendingIntent.FLAG_UPDATE_CURRENT);

这里 FLAG_ACTIVITY_SINGLE_TOP 打开现有活动,如果它位于任务堆栈的顶部。如果它不在顶部,而是在堆栈内部,FLAG_ACTIVITY_CLEAR_TOP 将删除目标活动顶部的所有活动并显示它。如果 Activity 不在任务堆栈中,则将创建新的。需要提到的一个至关重要的点 - PendingIntent.getActivity() 的第二个参数,即 requestCode 应该具有非零值(我什至在我的 sn-p 中将其称为 NON_ZERO_REQUEST_CODE),否则这些意图标志将不起作用。我不知道为什么会这样。标志 FLAG_ACTIVITY_SINGLE_TOP 可与 android:launchMode="singleTop" 互换 在清单中的活动标签中。

【讨论】:

用这些标志打了几个小时,想知道为什么改变我的意图标志并没有改变任何东西。非零请求代码...要提的至关重要的一点!!!现在工作!谢谢!【参考方案8】:

添加android training site 上的通知后,我遇到了类似的问题。这里没有其他答案对我有用,但是 this answer 确实对我有用。总结:

final Intent notificationIntent = new Intent(context, YourActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

【讨论】:

以上是关于意图 - 如果活动正在运行,请将其放在前面,否则启动一个新活动(来自通知)的主要内容,如果未能解决你的问题,请参考以下文章

php 按分类标准获取帖子的主要术语。如果使用Yoast主要术语,请将其返回,否则回退到第一学期。

当我想将现有的活动放在前面时,活动正在再次创建

如何将意图发送到正在运行的服务或后台活动?

如何使用意图来更新活动?

仅在活动运行时将意图从服务发送到活动

android方向 - 意图问题(相机)