Bell System Technical Journal

Bell System Technical Journal

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

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

На этой странице обсуждается каждый из этих подходов.

Простые случаи : onSaveInstanceState()

Обратный вызов onSaveInstanceState () предназначен для хранения относительно небольших объемов данных, необходимых для простой перезагрузки состояния контроллера пользовательского интерфейса, такого как активность или фрагмент, если система останавливается и позже воссоздает этот контроллер. Этот обратный вызов предназначен для обработки двух ситуаций:

Поскольку оба этих случая подразумевают, onSaveInstanceState () вызывается в ситуациях, когда действие останавливается (stop), но не завершается (not finished) системой. Например, если пользователь покидает приложение в течение нескольких часов, и система извлекает соответствующий процесс из памяти, система вызывает стандартную реализацию onSaveInstanceState () для сохранения каждого контроллера UI, имеющего ID. Позже, когда пользователь возвращается в приложение, система восстанавливает активность из сохраненного состояния.

Примечание: onSaveInstanceState () не вызывается, когда пользователь явно закрывает действие или в других случаях, когда вызывается функция finish().

Система автоматически сохраняет и восстанавливает большое количество данных пользовательского интерфейса для вас. Реализация по умолчанию onSaveInstanceState () сохраняет информацию о состоянии иерархии представлений активности, например текст в виджетах EditText или позиции прокрутки виджета ListView. Вы также можете сохранить пользовательские данные в этот пакет, переопределив обратный вызов onSaveInstanceState (). Если вы переопределите этот метод для сохранения дополнительной информации, не захваченной каждым отдельным объектом, вы должны вызвать реализацию по умолчанию, если вы не готовы самостоятельно сохранять состояния каждого объекта.

onSaveInstanceState () не предназначен для хранения больших объемов данных, таких как растровые изображения или сложные структуры данных, которые требуют длительной сериализации или десериализации. Сериализация может потреблять много памяти, если сериализуемые объекты сложны. Поскольку этот процесс происходит в основном потоке во время изменения конфигурации, сериализация может привести к отбрасыванию кадров и визуальному заиканию, если это займет слишком много времени. Поэтому вместо использования onSaveInstanceState () для сложных структур данных не забудьте сохранить такие структуры в локальном постоянном хранилище; это хорошая идея для хранения данных, как только он создан, чтобы свести к минимуму вероятность его потери. Затем используйте onSaveInstanceState () для хранения уникальных идентификаторов для каждого из этих объектов.

В следующем разделе этого документа содержится более подробная информация о сохранении более сложных данных.

Управление более сложными состояниями: разделяй и властвуй

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

Существует два общих способа, которыми пользователь может покинуть действие, что приведет к двум различным результатам, которые пользователь может ожидать:

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

Чтобы реализовать поведение для сложных структур данных в любой ситуации, вы используете Room, класс ViewModel и метод onSaveInstanceState () вместе. В каждом из этих подходов хранится разный тип данных, используемых в активности.

  • Локальная БД. Сохраняет все данные, которые вы не хотите потерять, если вы открываете и закрываете активность. Пример: коллекция объектов песни, которые могут включать аудиофайлы и метаданные.
  • ViewModel: сохраняет в памяти все данные, необходимые для отображения связанного с ней UI Controller. Пример: объекты песни самого последнего поиска и самый последний поисковый запрос.
  • onSaveInstanceState (): хранит небольшой объем данных, необходимых для простой перезагрузки состояния активности, если система останавливается, а затем воссоздает UI Controller. Вместо хранения сложных объектов здесь, надо сохранять сложные объекты в локальном хранилище, а уникальный идентификатор для этих объектов в onSaveInstanceState(). Пример: сохранение самого последнего поискового запроса.

В качестве примера рассмотрим действие, которое позволяет выполнять поиск в вашей библиотеке песен. Вот как следует обрабатывать различные события:

Когда пользователь добавляет песню, ViewModel немедленно поручает сохранение этих данных локально. Если эта недавно добавленная песня — это то, что должно отображаться в пользовательском интерфейсе, вы также должны обновить данные в объекте ViewModel, чтобы отразить добавление песни. Не забудьте сделать все insert в БД не из основного потока.

Когда пользователь ищет песню, любые сложные данные о песнях, которые вы загружаете из базы данных для UI Controller, должны быть немедленно сохранены в объекте ViewModel. Вы также должны сохранить запрос поиска в объекте ViewModel.

Когда активность переходит в фоновый режим, система вызывает onSaveInstanceState (). Вы должны сохранить поисковый запрос в bundle onSaveInstanceState(). Этот небольшой объем данных легко сохранить. Это также вся информация, необходимая для возвращения активности в текущее состояние.

Восстановление сложных состояний: повторная сборка частей

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

  • Активность воссоздается после остановки системы. Активность имеет запрос, сохраненный в bundle onSaveInstanceState (), и должна передать запрос в ViewModel. ViewModel видит, что она не имеет результатов поиска в кэше, и поручает загрузить результаты поиска, используя данный поисковый запрос.
  • Активность создается после изменения конфигурации. Активность имеет запрос, сохраненный в пакете (bundle) onSaveInstanceState(), и ViewModel уже имеет кэшированные результаты поиска. Вы передаете запрос из пакета onSaveInstanceState () в ViewModel, который определяет, что он уже загрузил необходимые данные и что ему не нужно повторно запрашивать базу данных.

Примечание. Когда изначально создается действие, пакет onSaveInstanceState() не содержит данных, а объект ViewModel пуст. Когда вы создаете объект ViewModel, вы передаете пустой запрос, который сообщает объекту ViewModel, что данных еще нет. Следовательно, активность начинается в пустом состоянии.

В зависимости от реализации вашей деятельности вам может вообще не понадобиться использовать onSaveInstanceState(). Например, браузер может вернуть пользователя к точной веб-странице, на которую он смотрел, прежде чем он вышел из браузера. Если ваша деятельность ведет себя таким образом, вы можете отказаться от использования onSaveInstanceState () и вместо этого сохранить все локально. В примере поиска песен это может означать сохранение самого последнего запроса в Shared Preferences.

Кроме того, когда вы открываете действие из намерения (intent), пакет bundle of extras доставляется в действие как при изменении конфигурации, так и при восстановлении системы. Если поисковый запрос был передан как intent extra, вы можете использовать этот пакет вместо onSaveInstanceState() bundle.

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

 

Читать ещё :   Руководство по архитектуре приложений. Часть 3

Читать еще