Мульти-резюме

В Android 9 (и ниже) приложения переходили в состояние PAUSED , когда:

  • Новое полупрозрачное действие было запущено поверх приложения, в то время как приложение все еще было видно (и, следовательно, не было остановлено).
  • Активность потеряла фокус, но не была загорожена и могла взаимодействовать с пользователем. Например, в многооконном режиме несколько активностей могут быть видны и получать сенсорный ввод одновременно.

Эти ситуации различаются по объему приостановки работы приложения, но их невозможно различить на уровне приложения.

В Android 10 все верхние фокусируемые действия в видимых стеках находятся в состоянии RESUMED . Это улучшает совместимость с режимами Multi-Window и MD для приложений, которые используют onPause() вместо onStop() для остановки обновления пользовательского интерфейса и взаимодействия с пользователем. Это означает:

  • Оба действия на разделенном экране возобновляются.
  • Все видимые сверху действия в режиме свободного окна возобновляются.
  • Действия на нескольких экранах можно возобновить одновременно.

Рисунок 1. Мультирезюме на складном устройстве

Рисунок 2. Мультирезюме в режиме рабочего стола

Действия могут находиться в состоянии PAUSED , когда на них невозможно сосредоточиться или они частично закрыты, например:

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

Такой подход указывает приложениям, что активность может получать ввод от пользователя только в состоянии RESUMED . До Android 10 активности также могли получать ввод в состоянии PAUSED (например, попробуйте одновременно коснуться обеих активностей на разделенном экране на устройстве под управлением Android 9).

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

Activity#onTopResumedActivityChanged(boolean onTop)

При вызове этот обратный вызов вызывается между Activity#onResume() и Activity#onPause() . Этот обратный вызов является необязательным и может быть пропущен, поэтому активность может перейти из состояния RESUMED в состояние PAUSED , не становясь самой верхней в системе. Например, в многооконном режиме. Поскольку этот обратный вызов является необязательным, он не является частью жизненного цикла активности и должен использоваться редко.

Предыдущая возобновленная сверху активность получает и завершает выполнение onTopResumedActivity(false) до того, как следующая возобновленная сверху активность получает onTopResumedActivity(true) если только предыдущей активности не требуется слишком много времени для обработки вызова метода и не истекает тайм-аут в 500 мс.

Совместимость

Чтобы сохранить совместимость при внедрении множественного резюме, рассмотрите следующие решения.

Несколько возобновленных действий в одном процессе приложения

  • Проблема. В Android 9 и ниже только одна активность в системе возобновляется за раз. Все переходы между активностями подразумевают приостановку активности перед возобновлением другой. Некоторые приложения и фреймворки (например, Flutter или LocalActivityManager Android) используют этот факт и сохраняют состояние возобновленной активности в синглтонах.
  • Решение. В Android 9 и ниже, если возобновляются два действия из одного и того же процесса, система возобновляет только то действие, которое выше в Z-порядке. Приложения, ориентированные на Android 10, могут поддерживать одновременное возобновление нескольких действий.

Одновременный доступ к камере

  • Проблемы . Эти проблемы также присутствуют в Android 9 и ниже. Например, полноэкранная и возобновленная активность может потерять фокус камеры на приостановленную активность сверху в режиме «картинка в картинке», но становится более уязвимой с более широким внедрением многооконного и многодисплейного режимов.
    • Из-за изменений, внесенных в состояние RESUME , приложения могут быть отключены от камеры даже во время возобновления . Чтобы решить эту проблему, приложения должны обрабатывать отключение камеры без сбоев. При отключении приложения получают обратный вызов disconnected, и все вызовы в API начинают выдавать CameraAccessException .
    • resizeableActivity=false не гарантирует эксклюзивный доступ к камере, поскольку другие приложения, использующие камеру, могут быть открыты на других дисплеях.
  • Решения. Разработчики должны включить логику для случая, когда приложение отключается от камеры. Если приложение отключается от камеры, оно должно отслеживать обратные вызовы доступности камеры, чтобы попытаться повторно подключиться и продолжить использование камеры. В дополнение к существующему обратному вызову CameraManager#AvailabilityCallback#onCameraAvailable() в Android 10 добавлен CameraManager#AvailabilityCallback#onCameraAccessPrioritiesChanged() , который охватывает случай, когда фокус (и приоритет камеры) переключается между несколькими возобновленными действиями. Разработчики приложений должны использовать оба этих обратных вызова, чтобы определить подходящее время для попытки получить доступ к камере.

Мульти-резюме

В Android 10 состояние жизненного цикла активности определяется видимостью и Z-порядком. Чтобы гарантировать, что правильное состояние после обновления видимости для активности и оценить, какое состояние жизненного цикла применимо, вызовите метод ActivityRecord#makeActiveIfNeeded() из разных мест. В Android 10 активный означает либо RESUMED , либо PAUSED и работает только в этих двух случаях.

В Android 10 возобновление активности отслеживается отдельно в каждом стеке, а не в одном месте в системе. Это связано с тем, что в многооконных режимах можно одновременно выполнять несколько переходов активности. Подробности см. ActivityStack#mInResumeTopActivity .

Обратный звонок по возобновленной активности

После действий, которые могут привести к изменению верхней активности (например, запуск активности, возобновление или изменение Z-порядка), вызывается ActivityStackSupervisor#updateTopResumedActivityIfNeeded() . Этот метод проверяет, изменилась ли верхняя возобновленная активность, и выполняет обновление при необходимости. Если предыдущая возобновленная активность не освободила состояние возобновления, то ей отправляется сообщение о потере состояния возобновления и на стороне сервера планируется тайм-аут ( ActivityStackSupervisor#scheduleTopResumedStateLossTimeout() ). Отчет о возобновленном состоянии отправляется следующей активности после того, как предыдущая освободила состояние или когда истекло время ожидания (см. использование:

ActivityStackSupervisor#scheduleTopResumedActivityStateIfNeeded()

Добавлен новый элемент транзакции TopResumedActivityChangeItem для сообщения клиентам об изменениях состояния возобновления верхнего уровня и использования архитектуры ActivityLifecycler из Android 9.

Состояние top-resumed хранится на стороне клиента, и каждый раз, когда активность переходит в RESUMED или PAUSED , она также проверяет, следует ли вызывать обратный вызов onTopResumedActivityChanged() . Это обеспечивает определенную развязку в коммуникации состояний жизненного цикла и состояния top-resumed между серверной и клиентской сторонами.