В 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
приложения могут отключаться от камеры даже в состоянии resumed . Для решения этой проблемы приложения должны обрабатывать отключение камеры без сбоев. При отключении приложения получают обратный вызов 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» между серверной и клиентской сторонами.