从通知创建的活动返回主活动

41
我正在尝试实现here中描述的行为,其中通知(或其他内容)在您的应用程序中启动“内部”活动,然后当用户按下返回键时,它会回到我的“主页”活动。
Android文档说:
在Back按钮的情况下,您应该通过将完整的向上导航路径插入到任务的返回堆栈中来使导航更加可预测。这允许忘记如何进入您的应用程序的用户在退出之前导航到应用程序的最高屏幕。
有没有好的方法来实现这一点?Stackoverflow上的其他问题建议使用一个意图来启动内部活动并告诉它启动主要活动,但这似乎是一个巨大的hack,我有些怀疑Google会在Gmail中使用它,并且我假设有一个像样的方法,因为他们提倡这种行为。
那么有没有不需要hack的方法来实现这个目标呢?
10个回答

82

啊哈,我只需要使用PendingIntent.getActivities()而不是getActivity()。还值得一提的是TaskStackBuilder

下面是一些代码:

    Intent backIntent = new Intent(ctx, MainActivity.class);
    backIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    Intent intent = new Intent(ctx, ConversationActivity.class);
    intent.putExtra("whatever", whatever);
    final PendingIntent pendingIntent = PendingIntent.getActivities(ctx, UNIQUE_REQUEST_CODE++,
            new Intent[] {backIntent, intent}, PendingIntent.FLAG_ONE_SHOT);

刚刚测试了一下,它的效果非常好。我最初怀疑如果应用程序已经在运行,当你去通知时可能会出现问题。也就是说,假设您的活动堆栈如下(右侧为最高):

[MainActivity] [SomeActivity]

当您点击 ConversationActivity 的通知时,会发生什么?

[MainActivity] [SomeActivity] [MainActivity] [ConversationActivity]

好吧,事实证明你神奇地得到了

[MainActivity] [SomeActivity] [ConversationActivity]

这正是我想要的,但我不知道它是如何做到的。我没有在任何活动中设置任何特殊选项。哦,算了吧!


很遗憾,这对我来说似乎不起作用。我的MainActivity确实再次被推入导航栈中,但仅适用于一个通知一次(我不会自动关闭它们)。有什么想法吗? - bompf
2
@bompf,这可能是因为在 PendingIntent.getActivities 中使用了 PendingIntent.FLAG_ONE_SHOT。我建议改用 PendingIntent.FLAG_CANCEL_CURRENT - Sam
5
谢谢,这对我有用,而“TaskStackBuilder”似乎不起作用。然而,你的代码导致了一个奇怪的情况:如果我通过启动器打开MainActivity,然后从通知中打开操作,在按返回按钮返回MainActivity后,再按返回按钮会再次回到MainActivity,就像这样:“[MainActivity] [MainActivity] [ConversationActivity]”。我通过将你的第二行代码更改为“backIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)”来解决这个问题。 - Sam
太棒了!TaskStackBuilder对我不起作用(https://developer.android.com/guide/topics/ui/notifiers/notifications.html),但是懒惰就是懒惰... - xyz

9

这是唯一真正对我有用的解决方案,谢谢先生! - glisu
这真的很有帮助。按照Android文档中的说明而不更改requestCode并没有起作用。 - Andreas Oikonomou
干得好,但如果我想用一个按钮返回怎么办?我应该使用什么! - Moataz

4
我知道两种实现方式:
  1. 从通知启动的活动中启动您的主页活动。这可能会变得非常棘手,因为您将不得不区分和跟踪各种可能的入口点。
  2. 始终从您的主页活动开始,检查是否正在通过通知启动,然后启动通知活动。这确保了一致的入口点,并且当用户按上键时,返回堆栈将在那里。
谢谢。

2
Intent displayIntent = new Intent(getApplicationContext(), TargetActivity.class);

displayIntent.putExtra("extra_id", "extra_key");

TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext());
stackBuilder.addParentStack(TargetActivity.class);
stackBuilder.addNextIntent(displayIntent);
stackBuilder.editIntentAt(1).putExtra("extra_id", "extra_key");

PendingIntent contentIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
        getApplicationContext(), "123").setSmallIcon(R.drawable.logo)
        .setContentTitle("GCM Notification")
        .setStyle(new NotificationCompat.BigTextStyle().bigText("Sample")).setContentText("sample text");

mBuilder.setContentIntent(contentIntent);

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(456, mBuilder.build());
stackBuilder.startActivities();

除了上述代码之外,还需要在您的AndroidManifest.xml文件中提供适当的父类名称。



0

我非常确定 singleTask 不能防止在同一个任务中出现多个活动实例。 - Timmmm

0
我知道我来晚了,但这可能会对某些人有所帮助。
只需为您想要使用通知打开的活动创建一个意图。 然后将Intent.FLAG_ACTIVITY_NEW_TASKIntent.FLAG_ACTIVITY_CLEAR_TASK设置为标志。
然后,您所需要做的就是使用您的意图作为参数创建一个PendingIntent
这是一个代码示例:
Intent intent = new Intent(this, NotificationActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

0

活动与任务相关联,任务只是后台堆栈中的一组活动。当您在通知上单击打开新活动时,该活动将作为独立活动打开并放入新任务中。这意味着只有通知活动和父活动存在。

只需在清单文件中将您的活动启动模式指定为“标准”,即可解决此问题。

Intent resultIntent = new Intent(getApplicationContext(),
                        ResultActivity.class);

PendingIntent resultPendingIntent =
    PendingIntent.getActivity(getApplicationContext(),0,resultIntent,PendingIntent.FLAG_UPDATE_CURRENT);

mBuilder.setContentIntent(resultPendingIntent); 

NotificationManager mNotificationManager = (NotificationManager)
    getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(notId, mBuilder.build());

清单:
<activity
            android:name="com.mns.exercisenotifications.ResultActivity"
            android:label="@string/app_name"
            android:launchMode="standard" >  <---
            <intent-filter>
                <action android:name="com.mns.exercisenotifications.ResultActivity" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

 </activity>

0

不错。

但请注意,它在3.0之前(API级别11之前)的系统上无法使用,因为PendingIntent.getActivities()在那里不可用。

对于通过Intent从通知访问活动并使返回按钮与您的应用程序协同一致(例如,详细活动返回到列表活动),构建后堆栈也是如此。


0

这个解决方案非常适用于这个问题

android:noHistory="true"

1
在哪里添加这个? - Narendra Singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接