Android: когда приложение было открыто нажатием на уведомление, нажатие на дальнейшие уведомления открывает только приложение, не изменяя активность

Согласно этой теме на StackOverflow, «Android запоминает намерение, которое было использовано для его запуска». Описанная там проблема - это именно то, через что я прохожу:

Когда приложение запускается в первый раз с Notification, это может все испортить. Вы запускаете приложение из Notification , и Android запоминает Intent использованный (из Notification), когда вы позже запускаете приложение (снова с Notification), Android сопоставляет Intent в Notification с Intent использованным для первого запуска приложения время и думает, что вы хотите перенести существующую задачу приложения из фонового режима на передний план.

Проблема: я не понимаю, почему Android считает, что Intent один и тот же. Хотя действие одно и то же, намерение имеет совершенно разные дополнения.

Когда я добавляю флаги к намерению, я могу решить эту проблему. Например:

Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK

Но моя цель — сохранить задний стек, который, конечно, не использует эти флаги.

Это приложение для веб-просмотра с некоторыми дополнительными экранами.

Проблема существует только тогда, когда приложение запускается через уведомление. Когда я запускаю его сам и ставлю на фон, все работает так, как я хочу.

Сценарий

  • not1 = уведомление с активностью MainActivity и дополнительными "openLink" =https://something.com/one
  • not2 = уведомление с активностью OtherActivity и некоторыми дополнениями
  • not3 = уведомление с активностью MainActivity и дополнительными "openLink" =https://something.com/two
  • приложение закрыто.

Что я хочу:

  1. пользователь нажимает not1, приложение запускается, открывает MainActivity, открывает ссылку в веб-просмотре
  2. пользователь нажимает not2, приложение открывает OtherActivity
  3. пользователь нажимает not3, приложение открывает MainActivity, открывает ссылку в веб-просмотре
  4. пользователь нажимает «назад», отображается OtherActivity из not2
  5. пользователь нажимает «назад», отображается MainActivity из not1

Как обстоят дела сейчас:

  1. пользователь нажимает not1, приложение запускается, открывает MainActivity, открывает ссылку в веб-просмотре ✅
  2. пользователь нажимает not2, приложение открывает OtherActivity ✅
  3. пользователь нажимает not3, приложение открывается и показывает OtherActivity. Не вызывать onCreate(). Если приложение находилось в фоновом режиме, при вызовах onResume() OtherActivity. Хотя предполагалось открыть MainActivity.

Мой код:

val pendingIntent = PendingIntent.getActivity(
    baseContext,
    notificationId,
    newIntent,
    PendingIntent.FLAG_IMMUTABLE
)

notificationBuilder = notificationBuilder.setContentIntent(pendingIntent)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(notificationId, notificationBuilder.build())

NotificationId уникален. дополнительные возможности newIntent уникальны. Я перепробовал все флаги, какие только есть. MainActivity (который имеет веб-просмотр) имеет режим запуска «singleTop», но, конечно, я пробовал без установки режима запуска.

Дальнейшие наблюдения:

  • Если я устанавливаю android:taskAffinity="" и пользователь нажимает not3, это работает, но портит задний стек. он просто вытягивает MainActivity перед стеком.
  • Я не могу сделать то, что говорит документация Android , а именно использовать TaskStackBuilder, потому что это не сохраняет задний стек. Он просто позволяет вам создать свой собственный задний стек (невозможно с помощью веб-просмотра).

Интересная ситуация. Попробуйте следующее: добавьте ДЕЙСТВИЕ к Intent, который вы вставили в Notification. Установите для ДЕЙСТВИЯ какую-нибудь случайную строку, чтобы она всегда была уникальной при каждом создании Notification. Дайте мне знать, если это поможет.

David Wasser 27.05.2024 15:11

Кроме того, если MainActivity имеет режим запуска singleTop и пользователь запускает MainActivity из Notification, а затем снова запускает MainActivity из Notification, это не создаст 2 экземпляра MainActivity в стеке. Это может (а может и не быть) то, что вы хотите. Кажется, ваш пост указывает на то, что в этом случае вы ожидаете иметь 2 экземпляра MainActivity в стеке.

David Wasser 27.05.2024 15:13

Это действительно сработало, я не могу в это поверить. Большое спасибо! Вы только что сделали мой день программирования. Мне нужно бесконечное количество обоих действий, но только новые экземпляры MainActivity в стеке, если новое намерение вызывает другое действие. Именно это и делает singleTop, но спасибо за подсказку.

Hillcow 27.05.2024 15:28

Это забавно, потому что это определенно не то, как вы должны использовать действия... Я чувствую, что Android должен как-то решить эту проблему.

Hillcow 27.05.2024 16:00

Я создал ответ с дополнительной информацией/объяснениями. Надеюсь, теперь понятно, что произошло и почему это изменение работает. Вам нужно сделать Intent «другими». Есть много способов сделать это, установка ДЕЙСТВИЯ — один из них.

David Wasser 27.05.2024 16:08

@DavidWasser, какой еще способ изменить намерение? Мне любопытно. Спасибо!

Hillcow 27.05.2024 18:52

Вы можете сделать Intent уникальным, установив для ДЕЙСТВИЯ или ДАННЫХ уникальное значение. Вы также можете установить имя компонента (пакет, класс), но это приведет к запуску другого Activity, поэтому это может не помочь.

David Wasser 28.05.2024 15:47
2
7
198
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Уникальное действие — это то, что позволяет Android различать намерения одного и того же действия:

newIntent.setAction(UUID.randomUUID().toString())

Большое спасибо @David Wasser за решение.

Ответ принят как подходящий

Ваша проблема в том, что когда пользователь нажимает not1, Android запускает приложение с помощью MainActivity и запоминает, что приложение было запущено с помощью MainActivity.

Когда пользователь нажимает not3, Intent в Notification имеет MainActivity, что соответствует Intent, который использовался для первоначального запуска приложения. (Примечание: Android не сравнивает «дополнительные элементы» при сравнении Intent), поэтому Android думает, что вы хотите перенести существующую задачу, содержащую приложение, из фона, что он и делает. В этом случае он не создает новый экземпляр MainActivity, не вызывает onNewIntent(), он просто выводит существующую задачу (в каком бы состоянии она ни находилась) на передний план.

Это то же самое поведение, что и при запуске приложения: нажмите ДОМОЙ, снова нажмите значок этого приложения. Android думает, что вы хотите вернуться в приложение, поэтому просто выводит его из фона.

Решение:

Добавьте ДЕЙСТВИЕ к Intent, который вы вставили в Notification. Установите для ДЕЙСТВИЯ какую-нибудь случайную строку, чтобы она всегда была уникальной при каждом создании Notification.

Это гарантирует, что всякий раз, когда пользователь нажимает Notification для запуска приложения, Intent не будет совпадать с Intent, который использовался для первоначального запуска приложения. Затем Android выведет приложение из фонового режима (если оно находится в фоновом режиме), создаст новый экземпляр Activity и поместит его в стек задач.

Только одно дополнение: в моем случае только приложение было открыто в последнем состоянии. Активность в намерении даже не была выведена на передний план.

Hillcow 27.05.2024 17:42

Правильно. Он просто переводит приложение в любое состояние, в котором оно находилось, из фонового на передний план. Именно это происходит, когда вы выходите из приложения (нажимая ДОМОЙ, уведомление или что-то еще), а затем возвращаетесь к нему, выбирая приложение из ПОСЛЕДНИЕ или нажимая значок приложения на ГЛАВНОМ экране. Вы возвращаетесь в приложение точно в том же состоянии, в каком вы его покинули. Тот же Activity, тот же Fragment, те же данные и т. д.

David Wasser 27.05.2024 17:44

Используйте только Intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

Не держит задний стек. На мой вопрос уже был дан ответ.

Hillcow 04.06.2024 12:56

Другие вопросы по теме