15

我有一个即将完成的应用程序,它具有非平凡的活动结构。有与此应用程序相关的推送通知,无论应用程序是前台/后台/非活动状态,选择通知条目都应该会调出特定活动。

如果应用程序未处于活动状态,我已经能够成功启动应用程序并自动导航到相应的部分。但是,当应用程序处于活动状态时,我遇到了问题。我将介绍问题的简化版本,以传达问题的性质,并根据需要发布我的应用程序活动结构和相关代码的详细信息(实际上,现在正在处理)。

因此,我的应用程序的活动堆栈(大大简化)如下所示:

A -> B -> X

其中A,根活动,是一个登录页面;B 有点像“主页”,X 是可以从主页启动的几个活动之一(但一次只有一个活动实例;因为这些只能从 B 启动)。

选择通知后,我需要应用程序自动导航到 B,无论它事先处于什么状态 - 无论是 [A]、[A -> B]、[A -> B -> X] 还是 [] (应用程序未激活)。

我的通知将 Intent 传递给活动 A。我尝试使用 CLEAR_TOP 和 NEW_TASK 标志,但没有。A 当前有launchmode=singleTask。这样做,我认为我正在解决所有可能的现有堆栈配置并将它们减少到 [A]。Intent 还带有一个额外的内容,将其标识为来自通知,而不是通常的启动。

Activity A,在将 Intent 识别为从通知发送时(它可以在 onCreate() 和 onNewIntent() 中执行此操作),向 Activity B 发送 Intent。此 Intent 包含 CLEAR_TOP 和 SINGLE_TOP。B 有launchmode=singleTop。

95% 的情况下,这可以按预期工作,并且在按下通知后,应用程序的堆栈为 [A -> B]。大约 5% 的时间,应用程序以某种方式以 [A -> B -> B] 堆栈结束。

关于这里发生的事情的任何想法,或者我做错了什么?

如果这是一个不平凡的问题,我会发布更多细节。事实上,现在发布更多细节......

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

单步调试调试器表明,每次 A 向 B 发送其意图时,B 的现有实例在被 onCreate() 之前是 onDestroy(),然后也调用了它的 onNewIntent()。这对我来说似乎很奇怪,并且表明我误解了我正在使用的标志(CLEAR_TOP 和 SINGLE_TOP),或者有其他东西干扰了它们。

我在调试中没有成功重现错误的堆栈结构。不知道是不是因为它没有在调试中发生,或者我只是没有尝试足够的时间。

正在制定的意图代码:

在 C2DM 接收器服务中:

protected void onMessage(Context context, Intent intent) {
    int icon = R.drawable.some_drawable;
    CharSequence tickerText = "blah";
    long when = System.currentTimeMillis();
    Notification notification = new Notification(icon, tickerText, when);

    //Context context = getApplicationContext(); //Don't need this; using the context passed by the message.
    CharSequence contentTitle = intent.getStringExtra("payload");
    CharSequence contentText = "Lorem ipsum dolor si amet,";
    Intent notificationIntent = new Intent(this, LoginPage.class);
    //notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); //Tried with and without
    notificationIntent.putExtra(PushManager.PUSH_INTENT, PushManager.PUSH_INTENT); //Indicator that this was send from notification

    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

    notificationManager.notify(PushManager.ALARM_NOTIFICATION_ID, notification);
}

在 LoginPage(Activity A)中,登录成功后:

Intent i = new Intent(LoginPage.this, TabHomePage.class);
// (If we're automatically going to tab 2, inform next activity)
if(fromNotification) {
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    i.putExtra(TabHomePage.TAB_NUMBER, TabHomePage.TAB_2);
}
startActivity(i);

有关活动堆栈结构的更多详细信息,请参见图片:

http://i89.photobucket.com/albums/k207/cephron/ActivityStack.png

这是千言万语:

Activity A 是一个登录页面;登录成功后,启动B。B是一个TabActivity,其中包含三个Activity(由C、D、E表示)。C、D 和 E 中的每一个实际上都是一个 ActivityGroup,其子活动模仿活动的通常堆栈行为。

因此,每个选项卡都包含自己的活动堆栈,并且在选项卡之间切换会更改当前正在由用户导航推送到/弹出哪些堆栈(每个选项卡都包含一个 ListActivities 堆栈,通过实体的层次结构浏览)。这些也可以在巨大的“B”TabActivity(由 X 表示)之外启动新的活动。

因此,从 Activity A 登录后,在接受更多用户输入之前,至少会创建三个 Activity: -B 已创建(并且可以看到,因为 TabWidget 现在位于屏幕顶部) -其中一个 ActivityGroups 已创建:无论哪个属于默认选项卡。这个 ActivityGroup 在屏幕上仍然没有显示,但是......它只显示其子活动堆栈的顶部活动。- 所以,最后,创建了 ActivityGroup 堆栈的“根”活动(在图片中,F 是此类 Activity 的示例)。此活动显示在 TabWidget 下方。

在每个选项卡被访问一次后,不再通过在选项卡之间切换来创建/销毁活动(不计算内存杀死)。在任何选项卡finish() 中按回该堆栈顶部的活动,显示其下方的活动。在任何选项卡中从根活动(如 F)按回完成整个 TabActivity,将用户送回 A。

传递给 B 的意图还指示它自动导航到与默认选项卡不同的选项卡。在我们最终得到一堆 [A -> B -> B] 的情况下,第一个 B 被导航到正确的选项卡,第二个是默认的。

4

1 回答 1

15

TL;博士; 不要同时使用 CLEAR_TOP 和 SINGLE_TOP

如果它只有 5% 的时间产生错误,则很可能是并发问题。你说你有 SINGLE_TOP | CLEAR_TOP 用于调用 Activity B。CLEAR_TOP 销毁 Activity B 的当前实例,并将意图传递给 onCreate()。SINGLE_TOP 不会破坏 Activity B 的当前实例,并将意图传递给 onNewIntent()。

当首先读取 SINGLE_TOP 标志时,intent 被传递到调用 onNewIntent() 的 Activity B 的当前实例。然后读取 CLEAR_TOP 并销毁 Activity B 并使用 onCreate() 创建一个新实例,一切正常。

当首先读取 CLEAR_TOP 时,Activity B 的现有实例被销毁,并使用 onCreate() 创建一个新实例。然后读取 SINGLE_TOP 并将意图传递给 onNewIntent() 。再一次,它成功了。

当同时读取 CLEAR_TOP 和 SINGLE_TOP 时,当前的 Activity 实例被销毁,CLEAR_TOP 调用 onCreate(),SINGLE_TOP 也调用 onCreate(),因为此时不存在 Activity B 的实例。因此,您最终得到 A->B->B。

于 2011-04-02T08:40:57.083 回答