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

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

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