Обрабатывать изменения конфигурации

Некоторые параметры устройства могут изменяться во время работы приложения. К ним относятся, помимо прочего:

  • Размер экрана приложения
  • Ориентация экрана
  • Размер и толщина шрифта
  • Местоположение
  • Темный режим против светлого режима
  • Наличие клавиатуры

Большинство этих изменений конфигурации происходит в результате взаимодействия с пользователем. Например, поворот или складывание устройства изменяет объем экранного пространства, доступного для вашего приложения. Аналогично, изменение настроек устройства, таких как размер шрифта, язык или предпочтительная тема, изменяет соответствующие значения в объекте Configuration .

Эти параметры обычно требуют достаточно существенных изменений в пользовательском интерфейсе вашего приложения, поэтому платформа Android имеет специальный механизм для обработки таких изменений. Этот механизм называется пересозданием Activity .

Активный отдых

Система пересоздает Activity при изменении конфигурации. Для этого система вызывает onDestroy и уничтожает существующий экземпляр Activity . Затем она создает новый экземпляр с помощью onCreate , и этот новый экземпляр Activity инициализируется новой, обновленной конфигурацией. Это также означает, что система пересоздает пользовательский интерфейс с новой конфигурацией.

Как правило, Activity выступает в качестве хоста для компонуемых объектов. При пересоздании Activity , Compose также пересоздает ваш пользовательский интерфейс, используя новые значения конфигурации.

Функция перезаписи помогает вашему приложению адаптироваться к новым конфигурациям, автоматически перезагружая его с использованием альтернативных ресурсов, соответствующих новой конфигурации устройства.

Пример отдыха

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

// In the res/values/strings.xml file
// <string name="compose">Jetpack Compose</string>

// In your Compose code
Text(
    text = stringResource(R.string.compose)
)

При создании Activity компонент Text считывает текущую конфигурацию (например, язык) и определяет соответствующий строковый ресурс.

Если язык меняется, система пересоздает активность. В этом случае Compose пересоздает пользовательский интерфейс. Поскольку stringResource считывает данные из текущей конфигурации, заголовок автоматически обновляется до правильного локализованного значения.

В процессе восстановления также удаляются все состояния, сохраненные в виде полей в рамках данной Activity .

Чтобы сохранить состояние пользовательского интерфейса при изменении конфигурации, используйте рекомендуемые шаблоны управления состоянием. Используйте ViewModel для данных и бизнес-логики, а rememberSaveable для состояния на уровне пользовательского интерфейса. Благодаря этим механизмам ваше состояние сохраняется при повторном создании Activity , в то время как пользовательский интерфейс обновляется, отражая новую конфигурацию.

Для получения дополнительной информации о сохранении состояния в Compose см. раздел «Сохранение состояния пользовательского интерфейса в Compose» .

Ожидания пользователей

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

Чтобы проверить, сохраняется ли состояние в вашем приложении, вы можете выполнять действия, которые приводят к изменению конфигурации как в фоновом, так и в активном режиме работы приложения. К таким действиям относятся:

  • Вращение устройства
  • Переход в многооконный режим
  • Изменение размера приложения в многооконном режиме или в окне произвольной формы.
  • Складывание складного устройства с несколькими дисплеями.
  • Изменение темы оформления системы, например, переключение с темного режима на светлый.
  • Изменение размера шрифта
  • Изменение системного языка или языка приложения
  • Подключение или отключение аппаратной клавиатуры
  • Подключение или отключение док-станции

Существует несколько подходов к сохранению соответствующего состояния при воссоздании Activity . Выбор подхода зависит от типа состояния, которое вы хотите сохранить:

  • Локальное хранение данных позволяет обрабатывать сбои процессов при работе со сложными или большими объемами данных. К постоянному локальному хранилищу относятся базы данных или DataStore .
  • Для управления состоянием пользовательского интерфейса в памяти во время активного использования приложения пользователем сохраняются такие объекты , как экземпляры ViewModel .
  • rememberSaveable используется для сохранения временного состояния пользовательского интерфейса при изменении конфигурации и завершении процессов, инициированных системой. Это подходит для состояния, зависящего от ввода пользователя, положения прокрутки или навигации, но не относящегося к ViewModel .

Чтобы подробно ознакомиться с API для каждого из этих методов и узнать, когда целесообразно использовать тот или иной, см. раздел «Сохранение состояний пользовательского интерфейса» .

Ограничить рекреационную деятельность

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

По умолчанию изменение конфигурации приводит к уничтожению и повторному созданию Activity, включая пользовательский интерфейс и любые объекты, производные от Activity. Если вы укажете, что ваша Activity сама обрабатывает изменение конфигурации, система предотвратит это. Вместо этого обновляется только объект Configuration , и Compose пересобирает ваш пользовательский интерфейс с новыми значениями.

Внесение изменений в конфигурацию непосредственно в Compose имеет ряд преимуществ:

  • Улучшенная производительность: перестройка пользовательского интерфейса обходится дешевле, чем полный цикл создания Activity, особенно при внесении незначительных изменений.
  • Плавная анимация: предотвращение перезапуска Activity позволяет запускать непрерывную анимацию при изменении конфигурации, например, плавные переходы между макетами при повороте устройства.
  • Сохранение состояния: Сохранение экземпляра Activity снижает риск временной потери состояния пользовательского интерфейса во время таких событий, как поворот экрана. Обратите внимание, что сохранение состояния по-прежнему необходимо обрабатывать при завершении процесса, инициированном системой.

Чтобы отключить повторное создание активности при определенных изменениях конфигурации, добавьте тип конфигурации в атрибут android:configChanges в записи <activity> в файле AndroidManifest.xml . Возможные значения указаны в документации для атрибута android:configChanges .

Следующий код манифеста отключает повторное создание Activity для MyActivity при изменении ориентации экрана и доступности клавиатуры:

<activity
    android:name=".MyActivity"
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
    android:label="@string/app_name">

Реагировать на изменения конфигурации

Jetpack Compose позволяет вашему приложению проще реагировать на изменения конфигурации. Однако, если вы отключите пересоздание Activity для всех изменений конфигурации, где это возможно, ваше приложение все равно должно корректно обрабатывать изменения конфигурации.

Объект Configuration доступен в иерархии пользовательского интерфейса Compose с помощью локального объекта композиции LocalConfiguration . При каждом его изменении компонуемые функции, считывающие данные из LocalConfiguration.current перекомпоновываются. Для получения информации о работе локальных объектов композиции см. раздел «Данные с локальной областью видимости с помощью CompositionLocal» .

Пример

В следующем примере компонент отображает дату в определенном формате. Компонент реагирует на изменения конфигурации системной локали, вызывая ConfigurationCompat.getLocales с LocalConfiguration.current .

@Composable
fun DateText(year: Int, dayOfYear: Int) {
    val dateTimeFormatter = DateTimeFormatter.ofPattern(
        "MMM dd",
        ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
    )
    Text(
        dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
    )
}

Чтобы избежать повторного создания Activity при изменении локали, Activity , в которой размещен код Compose, должна отказаться от учета изменений конфигурации локали. Для этого необходимо установить android:configChanges в locale|layoutDirection .

Изменения конфигурации: ключевые понятия и лучшие практики.

Вот основные понятия, которые необходимо знать при работе с изменениями конфигурации:

  • Настройки: Настройки устройства определяют, как пользовательский интерфейс отображается для пользователя, например, размер экрана приложения, язык или системную тему. В Compose вы можете получить доступ к значениям настроек с помощью LocalConfiguration .
  • Изменения конфигурации: Настройки изменяются в результате взаимодействия пользователя. Например, пользователь может изменить параметры устройства или способ физического взаимодействия с устройством. Предотвратить изменения конфигурации невозможно.
  • Перезапуск Activity : Изменения конфигурации по умолчанию приводят к перезапуску Activity . Это встроенный механизм для повторной инициализации состояния приложения в соответствии с новой конфигурацией.
  • Уничтожение Activity Activity При повторном создании Activity система уничтожает старый экземпляр Activity и создает на его месте новый. Старый экземпляр теперь устарел. Избегайте сохранения ссылок на объекты, находящиеся в рамках жизненного цикла, за пределами их предполагаемой области действия.
  • Состояние: Состояние старого экземпляра Activity отсутствует в новом экземпляре Activity , поскольку это два разных экземпляра объекта. Вместо того чтобы привязывать состояние к Activity, используйте рекомендуемые API для сохранения состояния приложения и пользователя, как описано в разделе «Сохранение состояний пользовательского интерфейса» .
  • Отказ от повторного создания действий: Чтобы отказаться от повторного создания действий при изменении конфигурации, необходимо, чтобы ваше приложение корректно обновилось в ответ на новые настройки. Для большинства приложений Compose это не рекомендуется.

Для обеспечения удобного пользовательского интерфейса следует соблюдать следующие рекомендации:

  • Будьте готовы к частым изменениям конфигурации: не следует предполагать, что изменения конфигурации происходят редко или никогда не случаются, независимо от уровня API, форм-фактора или набора инструментов пользовательского интерфейса. Когда пользователь вносит изменения в конфигурацию, он ожидает, что приложения обновятся и продолжат корректно работать с новой конфигурацией.
  • Сохранение состояния: Не теряйте состояние пользователя при повторном создании Activity . Сохраняйте состояние, как описано в разделе «Сохранение состояний пользовательского интерфейса с помощью таких API, как ViewModel и rememberSaveable .
  • Избегайте быстрого решения проблемы путем отказа от пересоздания Activity: не отказывайтесь от пересоздания Activity , чтобы избежать потери состояния. Отказ от пересоздания Activity требует выполнения обещания обработать изменение, и вы все равно можете потерять состояние из-за пересоздания Activity вследствие других изменений конфигурации, завершения процесса или закрытия приложения. Полностью отключить пересоздание Activity невозможно. Сохраняйте состояние, как описано в разделе «Сохранение состояний пользовательского интерфейса» .
  • Не избегайте изменений конфигурации: не устанавливайте ограничения на ориентацию, соотношение сторон или возможность изменения размера, чтобы избежать изменений конфигурации и повторного создания Activity . Это негативно сказывается на пользователях, которые хотят использовать ваше приложение так, как им удобно.

Обработка изменений конфигурации в зависимости от размера.

Изменения конфигурации, зависящие от размера экрана, могут происходить в любое время и более вероятны, если ваше приложение работает на устройствах с большим экраном , где пользователи могут переходить в многооконный режим . Они ожидают, что ваше приложение будет хорошо работать в такой среде.

Существует два основных типа изменений размера: существенные и незначительные. Существенное изменение размера — это такое изменение, при котором к новой конфигурации применяется другой набор альтернативных ресурсов из-за разницы в размере экрана, например, ширины, высоты или минимальной ширины. К таким ресурсам относятся как те, которые определяет само приложение, так и те, которые входят в его библиотеки.

Ограничить повторное создание активности для изменений конфигурации, зависящих от размера.

Если отключить пересоздание Activity для изменений конфигурации, зависящих от размера, система не пересоздает Activity . Вместо этого она получает вызов Activity.onConfigurationChanged . Все компонуемые объекты, считывающие LocalConfiguration.current , автоматически пересобираются, чтобы отразить новый размер.

При изменении конфигурации на основе размера, если в файле манифеста указано android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" пересоздание Activity отключается.

Дополнительные ресурсы

Для получения дополнительной информации об обработке изменений конфигурации см. следующие дополнительные ресурсы:

Документация

Просмотры контента