Intereting Posts
Как установить название DialogFragment? Как проверить, является ли мое приложение стандартной пусковой установкой Ошибка Eclipse – parseSdkContent – не распознавание файлов XML Удалить элемент из «Частных библиотек Android», который отсутствует в папке с папками моего проекта Что произойдет, если я использую один и тот же идентификатор для нескольких виджетов в разных макетах? Использование google-аккаунта для входа в Android-приложение Пример SDK для Android + ошибка «gradle build»: org.gradle.api.tasks.TaskExecutionException: выполнение не выполнено для задачи Проблема обновления приложений для Android Андроидная и javafx облегченная совместимость Как использовать сервисных работников в Android-приложении Cordova? В чем разница между длинным и длинным в коде Android? Как настроить панель контекстного действия с помощью appCompat в материальном дизайне Правильный подход к тестированию устройств Android Android: Создайте spinner программно из массива Установить программный код textCursorDrawable

SINGLE_TOP | CLEAR_TOP, похоже, работает 95% времени. Почему 5%?

У меня есть законченное приложение с нетривиальной структурой деятельности. Существуют уведомления о нажатиях, связанные с этим приложением, и выбор записи уведомления должен вызывать конкретную активность независимо от того, является ли приложение приоритетным / фоновым / неактивным.

Если приложение неактивно, я смог успешно запустить приложение и автоматически перейти к соответствующей части. Однако, когда приложение активно, у меня проблема. Я представлю упрощенную версию проблемы, чтобы сообщить о характере проблемы, и я буду публиковать детали структуры деятельности моего приложения и соответствующего кода по мере необходимости (фактически, работая над этим сейчас).

Итак, стек активности моего приложения (значительно упрощен) выглядит следующим образом:

A -> B -> X

Где A, корневая активность, является страницей входа; B – это что-то вроде «домашней страницы», а X – одно из нескольких действий, которые можно запустить с домашней страницы (но только один экземпляр активен одновременно, поскольку их можно запустить только с B).

Когда уведомление выбрано, мне нужно, чтобы приложение автоматически переходило на B, независимо от того, какое состояние оно было предварительно, – [A], [A -> B], [A -> B -> X] или [] ( Приложение неактивно).

Мое уведомление передает намерение в действие A. Я пробовал использовать флаги CLEAR_TOP и NEW_TASK, и ни один. В настоящее время у него есть startmode = singleTask. Сделав это, я полагаю, что я обращаюсь ко всем возможным существующим конфигурациям стеков и сокращаю их до [A]. В Intent также есть дополнительный, который идентифицирует его как исходящий из уведомления, в отличие от обычного запуска.

Действие A после определения намерения как отправленное из уведомления (оно может сделать это как в onCreate (), так и onNewIntent ()), отправляет Intent для Activity B. Этот Intent содержит CLEAR_TOP и SINGLE_TOP. B имеет startmode = 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 (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

И вот тысяча слов:

Активность A – это страница входа в систему; При успешном входе в систему он запускает B. B – это TabActivity, который содержит три действия внутри него (представленные C, D, E). Каждый из C, D и E фактически является ActivityGroup, дочерние действия которого имитируют обычное поведение стека в действиях.

Таким образом, каждая вкладка содержит свой собственный стек действий и переключение между изменениями вкладок, которые из этих стеков в настоящее время подталкиваются / вывозятся с помощью навигации пользователя (каждая вкладка содержит стек ListActivities, просматривающий иерархическую структуру сущностей). Они также могут запускать новые действия за пределами гигантской «В» TabActivity (представленной X).

Таким образом, при входе из Activity A, как минимум три действия создаются до того, как принимается больше пользовательского ввода: -B создается (и видно, из-за TabWidget сейчас в верхней части экрана) – Создана одна из ActivityGroups : Какой бы ни был выбран вкладка по умолчанию. Однако этот ActivityGroup пока не отображается на экране, но он показывает только верхнюю активность его стека дочерних действий. -Так, наконец, создается «корневая» активность этого стека ActivityGroup (на рисунке F – пример такой активности). Эта активность отображается ниже TabWidget.

После того, как каждая вкладка была посещена один раз, больше никаких действий не создается / уничтожается путем переключения между вкладками (не считая убиваний памяти). Нажатие на любую вкладку завершает () операцию в верхней части этого стека, показывая одну под ней. Нажатие назад из корневой активности (например, F) на любой вкладке завершает всю TabActivity, отправляя пользователя обратно на A.

Цель, переданная B, также дает указание ей автоматически перейти на другую вкладку, чем по умолчанию. В случае, когда мы заканчиваем стек [A -> B -> B], первый B перемещается на правильную вкладку, а второй – по умолчанию.

Solutions Collecting From Web of "SINGLE_TOP | CLEAR_TOP, похоже, работает 95% времени. Почему 5%?"

TL; DR; Не используйте CLEAR_TOP с SINGLE_TOP одновременно

Если он производит ошибку только в 5% случаев, это, скорее всего, будет проблемой параллелизма. Вы сказали, что у вас есть SINGLE_TOP | CLEAR_TOP для вызова Activity B. CLEAR_TOP уничтожает текущий экземпляр Activity B и намерение передается onCreate (). SINGLE_TOP не уничтожает текущий экземпляр Activity B и доставляет намерение onNewIntent ().

Когда сначала считывается флаг SINGLE_TOP, цель доставляется к текущему экземпляру Activity B, вызывающему onNewIntent (). Затем считывается CLEAR_TOP и активность B уничтожается, а новый экземпляр создается с помощью onCreate (), и все работает нормально.

Когда сначала считывается CLEAR_TOP, существующий экземпляр Activity B уничтожается, а новый создается с помощью onCreate (). Затем SINGLE_TOP считывается, и намерение также передается onNewIntent (). Опять же, это сработает.

Когда CLEAR_TOP и SINGLE_TOP считываются одновременно, текущий экземпляр активности уничтожается, а CLEAR_TOP вызывает onCreate (), а SINGLE_TOP вызывает onCreate (), потому что на данный момент не существует экземпляра Activity B. Таким образом, вы получаете A-> B-> B.