У меня есть почти готовое приложение с нетривиальной структурой деятельности. С этим приложением связаны push-уведомления, и выбор записи уведомления должен вызывать определенную активность независимо от того, является ли приложение передним / задним / не активным.
Если приложение не активно, я смог успешно запустить приложение и автоматически перейти к соответствующей части. Однако, когда приложение активно, у меня проблема. Я представлю упрощенную версию проблемы, чтобы сообщить природу проблемы, и я опубликую детали структуры деятельности моего приложения и соответствующий код по мере необходимости (фактически, работая над этим сейчас).
Итак, стек активности моего приложения (значительно упрощенный) выглядит следующим образом:
A -> B -> X
Где A, корневая активность, является страницей входа в систему; B - это что-то вроде «домашней страницы», а X - это одно из нескольких действий, которые можно запустить с домашней страницы (но одновременно активен только один экземпляр; так как они могут быть запущены только из B).
Когда выбрано уведомление, мне нужно, чтобы приложение автоматически переместилось на B, независимо от того, в каком состоянии оно было предварительно - будь то [A], [A -> B], [A -> B -> X] или [] (приложение не активно).
Мое уведомление передает намерение для действия A. Я попытался использовать флаги CLEAR_TOP и NEW_TASK, но ни одного. В настоящее время есть launchmode = singleTask. Делая это, я полагаю, что обращаюсь ко всем возможным существующим конфигурациям стека и сокращаю их до [A]. Намерение также содержит дополнительный элемент, который идентифицирует его как исходящий из уведомления, в отличие от обычного запуска.
Операция A, после идентификации намерения как отправляемого из уведомления (он может сделать это как в onCreate (), так и в onNewIntent ()), отправляет намерение в действие B. Это намерение содержит CLEAR_TOP и SINGLE_TOP. B имеет режим запуска = singleTop.
95% времени, это работает как нужно, и после нажатия уведомления, стек приложения - [A -> B].
Примерно в 5% случаев приложение каким-то образом заканчивается стеком [A -> B -> B].
Есть идеи о том, что здесь происходит, или что я делаю не так?
Я опубликую более подробно, если это окажется нетривиальной проблемой. Фактически, публикуя больше деталей сейчас ...
~~~~~~~~~~~~~~~~~~~~~~~ ПОДРОБНОЕ ОПИСАНИЕ ~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
Шаги по отладчику показывают, что каждый раз, когда A отправляет свое намерение B, существующим экземпляром B является onDestroy () 'd, а затем onCreate ()' d и затем также вызывается его 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 (Задание 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
А вот тысяча слов:
Действие A - страница входа в систему; при успешном входе в систему запускается B.
B - это TabActivity, которое содержит в себе три вида деятельности (представлены C, D, E).
Каждый из C, D и E на самом деле представляет собой группу ActivityGroup, чьи дочерние действия имитируют обычное поведение стека действий.
Таким образом, каждая вкладка содержит свой собственный стек действий, и переключение между вкладками изменяет, какой из этих стеков в настоящее время перемещается / извлекается навигацией пользователя (каждая вкладка содержит стек ListActivities, просматривая иерархическую структуру объектов ). Они также могут начинать новые действия за пределами гигантской функции B TabActivity (представлена X).
Таким образом, после входа из действия A создается по крайней мере три действия, прежде чем будет принято больше пользовательских данных: -B создан (и виден, потому что TabWidget теперь вверху экрана) -Один изГруппы деятельности созданы: какая из них принадлежит вкладке по умолчанию.Эта ActivityGroup остается непредставленной на экране, однако ... она показывает только верхнюю активность своего стека дочерних действий.-Так наконец, создается «корневая» активность этого стека ActivityGroup (на рисунке F - пример такой деятельности).Это действие отображается под TabWidget.
После того, как каждая вкладка была посещена один раз, больше не создаются и не удаляются действия при переключении между вкладками (не считая убийств памяти).Нажатие в любой вкладке finish () приводит к тому, что Activity находится наверху этого стека, показывая под ним.Нажатие обратно из корневого действия (например, F) на любой вкладке завершает весь TabActivity, отправляя пользователя обратно к A.
Намерение, переданное B, также дает ему команду автоматически переходить на другую вкладку, отличную от стандартной.В случае, когда мы получаем стек [A -> B -> B], первый B перемещается на правильную вкладку, а второй по умолчанию.