如果应用程序处于非活动状态,则我已成功启动应用程序并自动导航到适当的部分。然而,当应用程序处于活动状态时,我遇到了问题。为了传达问题的性质,我将提供一个简化版本,并根据需要发布我的应用程序的活动结构和相关代码的详细信息(实际上正在处理这个问题)。
因此,我的应用程序的活动堆栈(大大简化)如下所示:
A -> B -> X
其中A是根活动,是登录页面;B是一种“主页”,X是可以从主页启动的多个活动之一(但同时只能有一个实例处于活动状态;因为这些只能从B启动)。
当选择通知时,我需要应用程序自动导航到B,无论之前处于什么状态——无论是[A]、[A->B]、[A->B->X]还是[](应用程序不活动)。
我的通知向活动A传递一个意图。我尝试使用CLEAR_TOP和NEW_TASK标志,以及不使用任何标志。 A当前具有launchmode=singleTask。这样做,我认为我正在处理所有可能的现有堆栈配置,并将它们减少到[A]。该意图还携带一个额外的标识符,表明它来自通知,而不是普通启动。
活动A在确定意图是从通知发送的(它可以在onCreate()和onNewIntent()中都这样做)后,向活动B发送一个意图。此意图包含CLEAR_TOP和SINGLE_TOP。 B具有launchmode=singleTop。
95%的时间,这个操作按预期工作,按下通知后,应用程序的堆栈为[A->B]。 大约5%的时间,应用程序以[A->B->B]的堆栈结束。
对此有什么想法,或者我做错了什么吗?
如果这是一个非平凡的问题,我会发布更多详细信息。事实上,现在发布更多详细信息...
通过调试器逐步进行显示,每次A将其意图发送给B时,现有的B实例都会被销毁(在onCreate()之前),然后还会调用其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);
}
在登录页面(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);
关于Activity堆栈结构的更多细节,请看下面的图片:
http://i89.photobucket.com/albums/k207/cephron/ActivityStack.png
以下是详细说明:
Activity A 是一个登录页面,成功登录后会启动B。 B是一个TabActivity,在其中包含三个活动(用C、D、E表示)。 每个活动(C、D、E)实际上都是一个ActivityGroup,其子活动模拟了常规活动的堆栈行为。
因此,每个选项卡都包含自己的活动堆栈,切换选项卡会改变用户导航时当前正在被推入/弹出的这些堆栈之一(每个选项卡都包含一个浏览实体层次结构的ListActivities堆栈)。它们还可以启动超出巨大的'B' TabActivity范围的新活动(由X表示)。
因此,在从Activity A登录后,至少需要创建三个活动才能接受更多用户输入: -创建B(并且由于TabWidget现在位于屏幕顶部,所以可以看到它) -创建ActivityGroups中的一个:属于默认选项卡的那个。但此ActivityGroup不会在屏幕上显示,它只显示其子活动堆栈的顶部活动。 -因此,该ActivityGroup堆栈的“根”活动被创建(在图片中,F是这样一种活动的示例)。此活动在TabWidget下方显示。
访问每个选项卡一次后,切换选项卡不会再创建/销毁任何活动(不包括内存清理)。 在任何选项卡中按返回键会完成该堆栈顶部的活动,并显示其下面的一个活动。 从任何选项卡中的根活动(如F)按返回键会完成整个TabActivity,将用户发送回A。
传递给B的意图还指示它自动导航到与默认选项卡不同的选项卡。在我们最终得到[A -> B -> B]堆栈的情况下,第一个B会导航到正确的选项卡,而第二个则位于默认选项卡。