Site icon AppTractor

Введение в Jetpack DataStore

DataStore — это библиотека хранения данных Jetpack, которая обеспечивает безопасный и последовательный способ хранения небольших объемов данных, таких как настройки или состояние приложения. Он основан на корутинах Kotlin и Flow, которые обеспечивают асинхронное хранение данных. DataStore  призван заменить SharedPreferences, поскольку является потокобезопасным и неблокирующимся. Он предоставляет две разные реализации: Proto DataStore, в котором хранятся типизированные объекты (поддерживаемые буферами протокола), и Preferences DataStore, в котором хранятся пары ключ-значение. В дальнейшем, когда мы просто используем термин DataStore, это относится к обеим реализациям, если не указано иное.

В этом посте мы более подробно рассмотрим DataStore — как он работает, какие реализации предоставляет и каковы разные варианты его использования. Мы также рассмотрим, какие преимущества и улучшения он дает по сравнению с SharedPreferences, и почему это делает DataStore достойным вашего внимания.

DataStore против SharedPreferences

Скорее всего, вы уже использовали SharedPreferences в своих приложениях. Также вполне вероятно, что вы сталкивались с проблемами с SharedPreferences, которые трудно воспроизвести — наблюдались странные сбои в вашей аналитике из-за необработанных исключений, блокировка UI-потока при совершении вызовов или несогласованные, сохраняемые данные в вашем приложении. DataStore был создан для решения всех этих проблем.

Давайте посмотрим на прямое сравнение между SharedPreferences и DataStore:

Асинхронный API

При использовании большинства API-интерфейсов хранения данных вам часто требуется асинхронно получать уведомления об изменении данных. SharedPreferences предлагает некоторую асинхронную поддержку, но только для получения обновлений об измененных значениях через OnSharedPreferenceChangeListener. Однако этот колбек по-прежнему вызывается в основном потоке. Точно так же, если вы хотите перенести работу по сохранению файлов в фоновый режим, вы можете использовать SharedPreferences apply(), но имейте в виду, что и это заблокирует поток пользовательского интерфейса в fsync(), что может привести к зависаниям и ошибкам ANR. Это может произойти в любое время, когда служба запускается или останавливается, а также Activity приостанавливается или останавливается. Для сравнения, DataStore предоставляет полностью асинхронный API для извлечения и сохранения данных, используя возможности корутин Kotlin и Flow, что снижает риск блокировки вашего UI- потока.. Для тех, кто не знаком с Kotlin Flow, это просто поток значений, которые можно вычислять асинхронно.

Синхронная работа

SharedPreferences API поддерживает синхронную работу по умолчанию. Однако его синхронный commit() для изменения сохраненных данных может показаться безопасным для вызова в потоке пользовательского интерфейса, но на самом деле он выполняет более тяжелые операции ввода-вывода. Это рискованный сценарий, который может привести и часто приводит к ошибкам ANR и замедлениям интерфейса. Чтобы предотвратить это, новы подход не предлагает готовой к использованию синхронной поддержки. DataStore сохраняет настройки в файле и незаметно выполняет все операции с данными в Dispatchers.IO, если не указано иное, не блокируя поток пользовательского интерфейса.

Однако можно совместить DataStore и синхронную работу с небольшой помощью билдеров корутин, как мы увидим позже.

Обработка ошибок

SharedPreferences может вызывать ошибки синтаксического анализа как исключения во время выполнения, делая ваше приложение уязвимым для сбоев. Например, ClassCastException — это обычно возникающее исключение, выдаваемое API, когда запрашивается неправильный тип данных. DataStore позволяет перехватывать любые исключения, возникающие при чтении или записи данных, полагаясь на механизм сигнализации ошибок Flow.

Безопасность типов

Использование пар ключ-значение для сохранения и извлечения данных не обеспечивает защиту типов. Однако с Proto версией вы можете заранее определить схему для своей модели данных и получить дополнительные преимущества полной безопасности типов.

Согласованность данных

Отсутствие гарантий атомарности SharedPreferences означает, что вы не можете полагаться на то, что изменения ваших данных будут отражаться всегда и везде. Это может быть опасно, особенно потому, что весь смысл этого API заключается в постоянном хранении данных. Для сравнения, новый полностью транзакционный API обеспечивает надежные гарантии ACID, поскольку данные обновляются в атомарных операциях чтения-изменения-записи. Он также обеспечивает согласованность «чтение после записи», иллюстрируя тот факт, что все завершенные обновления будут отражены в значениях чтения.

Поддержка миграции

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

Preferences против Proto DataStore

Теперь, когда мы увидели, какие преимущества предлагает новая система по сравнению с SharedPreferences, давайте поговорим о том, как сделать выбор между двумя его реализациями — Preferences и Proto DataStore.

Preferences DataStore считывает и записывает данные на основе пар ключ-значение без предварительного определения схемы. Хотя это может показаться похожим на SharedPreferences, помните обо всех упомянутых выше улучшениях, которые привносит DataStore. Не обманывайтесь их совместным использованием термина «Preferences» в именовании — они не имеют ничего общего и исходят из двух совершенно разных API.

Proto DataStore хранит типизированные объекты, поддерживаемые буферами протокола, обеспечивая безопасность типов и устраняя необходимость в ключах. Protobuf быстрее, меньше, проще и менее неоднозначны, чем XML и другие подобные форматы данных. Если вы не использовали их раньше, не бойтесь! Их очень просто понять и начать использовать. Хотя Proto DataStore требует изучения нового механизма сериализации, мы считаем, что его преимущества, особенно безопасность типов, того стоят.

Выбирая между ними, следует учитывать следующее:

DataStore против Room

Вы можете спросить: «А почему бы просто не использовать Room для хранения моих данных?». И это справедливый вопрос! Итак, давайте посмотрим, какое место во всем этом занимает Room.

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

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

Как выбрать между DataStore и Room

Продолжение следует

Мы подробно рассмотрели DataStore — как он работает, изменения и улучшения, которые он приносит, и как выбрать между двумя его реализациями. В следующих двух статьях мы обсудим Proto и Preferences DataStore — как создавать, читать и записывать данные, обрабатывать любые ошибки, а также как мигрировать с SharedPreferences. Оставайтесь на связи!

Источник

Exit mobile version