Одновременная работа нескольких приложений

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

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

В этих ситуациях приложение должно приостановить работу на разное время, но на уровне приложения это неразличимо.

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

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

Рисунок 1. Одновременная работа нескольких приложений на складном устройстве

Рисунок 2. Одновременная работа нескольких приложений в режиме компьютера

Объекты могут находиться в состоянии PAUSED, когда на них нельзя сфокусироваться или они частично закрыты, например:

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

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

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

Activity#onTopResumedActivityChanged(boolean onTop)

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

Предыдущее возобновленное действие получает и завершает выполнение 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 состояние жизненного цикла объекта activity определяется его видимостью и порядком Z. Чтобы убедиться, что после обновления видимости объекта activity задано правильное состояние, и определить, какое состояние жизненного цикла применимо, вызовите метод ActivityRecord#makeActiveIfNeeded() из разных мест. В Android 10 активный режим означает, что используется приложение RESUMED или PAUSED.

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

Обратный вызов для возобновления работы приложения, находящегося на переднем плане

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

ActivityStackSupervisor#scheduleTopResumedActivityStateIfNeeded()

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

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