Рекомендуемое Jetpack решение для хранения данных с использованием Protobufs, обеспечивающее безопасность типов.

Вступление

SharedPreferences - общий способ хранения пар ключ-значение в локальном хранилище. Datastore заменяет SharedPreferences, устраняя его недостатки. Datastore - это передовое решение для хранения данных, созданное с использованием сопрограмм Kotlin и Flow для хранения данных асинхронно, согласованно и транзакционно. Есть два способа хранить данные в DataStore. Это Preferences DataStore и Proto DataStore. Пожалуйста, ознакомьтесь с моим предыдущим постом о введении в Datastore и Preferences DataStore.



В этом посте мы узнаем больше о следующем:
- Proto DataStore
- Protobufs
- Базовая реализация Proto DataStore

Для понимания этого необходимо знакомство с сопрограммами и Kotlin Flow.

Если вы хотите перейти непосредственно к базе кода, загляните в репозиторий GitHub.

Что такое Proto DataStore?

Мы привыкли к системе пары ключ-значение для хранения данных в общих настройках и хранилище данных предпочтений. Однако Proto DataStore хранит данные как экземпляры настраиваемого типа данных, а не пар "ключ-значение". Proto DataStore нуждается в предопределенной схеме с типами данных и экземплярами, которые необходимо сохранить. Такой подход к схеме помогает обеспечить безопасность типов с помощью предопределенных типов данных. Нам нужно определить схему, используя буферы протокола.

  • Сохраняет данные как экземпляры настраиваемого типа данных.
  • Определяет схему с использованием буферов протокола. Использование Protobufs позволяет сохранять строго типизированные данные.
  • Они быстрее, меньше, проще и менее неоднозначны, чем XML и другие подобные форматы данных.

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

Что такое буферы протокола?

Буферы протокола, обычно называемые Protobufs, являются независимыми от языка и платформы механизмами сериализации данных. Protobufs лучше всего подходят для сценариев, где требуется более быстрая связь по сети или для хранения данных. Google создал формат ProtoBuf в 2008 году. Это альтернативное решение JSON и XML для максимально быстрой сериализации и десериализации данных.

Текущая версия Protobuf - proto3. Мы будем использовать эту версию proto3 позже для создания нашего хранилища данных proto. Важно знать механизм Protobufs. В этом механизме мы используем прото-файлы с .proto расширениями, куда мы записываем данные для сериализации. Прототипы файлов содержат типы сообщений, в которых мы определяем наши данные.

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

{
 is_logged_in: true,
 user_name: "Android"
}

Теперь давайте создадим для этого формат файла proto

syntax = "proto3";
message UserData{
  bool is_logged_in = 1;
  string user_name = 2;  
}

Для каждого поля нам нужно определить Field Types, Field Numbers, Field Rules и т. Д. Чтобы узнать больше о Protobufs, ознакомьтесь с Руководством Google для Protobufs

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

Хватит разговоров, перейдем к кодированию ...

Выполнение

Давайте создадим UserDataStore, где мы будем хранить данные, относящиеся к пользователю.

Шаг 1

Здесь недостаточно простого добавления зависимости. Нам нужно

  • добавить плагин Protobuf и настроить Protobuf
  • добавить зависимости Protobuf и Proto DataStore.

Шаг 2

Когда мы закончили настройку Gradle, перейдем к созданию прото-файла с обязательными полями. Создайте прото-каталог в app/src/main/. Давайте добавим прототип файла в каталог proto с именем user_store с расширением .proto.

Шаг 3: Добавление содержимого в прото-файл.

Нам нужно определить версию, пакет, параметры java_multiple_files и определить наш объект сообщения с обязательными полями. Давайте сохраним два поля is_logged_in типа Boolean и user_name типа string. Как мы уже видели в разделе Protobuf, синтаксис прототипа файла будет таким же.

syntax = "proto3";

option java_package = "com.sample.android_sample_preference_datastore";
option java_multiple_files = true;

message UserStore {
    bool is_logged_in = 1;
    string user_name = 2;
}

Мы можем добавить несколько сообщений, в которых каждое отдельное сообщение имеет сгенерированный класс. Если у нас есть данные, связанные с приложением, мы можем создать AppData, а для пользовательского материала - UserStore и т. Д.

Шаг 4

Перестройте свой проект и убедитесь, что UserStore.java должен быть создан с использованием app/build/generated/source/proto или двойной смены, и проверьте имя UserStore. Просто просмотрите обзор UserStore, где есть различные методы для хранения, извлечения данных, создания экземпляров UserStore и прочего.

Шаг 5

Пришло время создать сериализатор. Давайте создадим класс, реализующий Serializer<T>, где T - это тип сообщения, определенный в файле proto. Это Serializer говорит хранилищу данных, как читать и записывать тип данных, который мы определили в файле proto. Создадим UserStoreSerializer

Примечание. Лучше всего запускать блоки readFrom и writeTo внутри withContext (Dispatchers.IO) {} и обрабатывать исключения в обоих случаях, поскольку методы readFrom и writeTo могут вызывать исключение ввода-вывода. Нам нужно определить несколько сериализаторов, если есть несколько типов сообщений.

Шаг 6: Создание экземпляра Proto DataStore

Мы можем использовать dataStore делегат для создания экземпляра Datastore. Делегату нужны два обязательных ввода: имя и сериализатор.

Делегат dataStore гарантирует, что у нас есть единственный экземпляр DataStore с этим именем в нашем приложении.

Шаг 7. Считайте операцию из экземпляра прототипа хранилища данных.

Как и в случае с Preference Datastore, мы можем использовать DataStore.data для отображения Flow определенного свойства из сохраненного состояния экземпляра.

Для обработки исключений при чтении оберните блокировкой

Шаг 8: операция Wite на экземпляре хранилища данных прототипа

У нас есть updatedata() функции, которые обновляют данные транзакционно в атомарной операции чтения-изменения-записи. Мы получаем текущее состояние свойства, затем записываем его и сохраняем.

Пример

Теперь давайте проверим их вместе на простом примере, как мы это сделали в случае хранилища данных о предпочтениях. Давайте сохраним и получим логическое значение (состояние входа пользователя в систему), используя шаблон репозитория внутри действия. В этом примере шаблон репозитория - это не что иное, как простой интерфейс и класс, реализующий интерфейс, в котором мы выполняем операции сохранения и выборки в экземпляре protoDataStore. Для простоты давайте вручную добавим экземпляр protoDataStore в реализацию репозитория. Поскольку мы продолжаем наблюдать текучесть, излучаемую хранилищем данных о предпочтениях, данные будут автоматически изменены.

Шаг 1

Давайте создадим простой XML с двумя кнопками для входа и выхода.

Шаг 2

Давайте создадим Activity, в котором мы раздуваем вышеуказанный макет и одним щелчком кнопки Login мы сохраняем состояние входа пользователя в систему как истинное, а при щелчке другого мы сохраняем false. Кроме того, мы создаем экземпляр proto DataStore, и будет следить за состоянием входа пользователя в систему. В зависимости от состояния мы добавляем текст и цвет фона

Нам нужно добавить зависимость lifecycle-runtime-ktx, чтобы использовать lifecycleScope.

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"

Шаг 3

Давайте создадим ProtoUserRepo с двумя методами для сохранения и получения состояния входа пользователя.

Шаг 4

Давайте предоставим ProtoUserRepoImpl реализацию ProtoUserRepo

Это все, что мы сделали. Запустите приложение и проверьте результат.

Вывод

Если у вас есть какие-либо проблемы при выполнении фрагментов кода, пожалуйста, посетите репозиторий GitHub для удобного доступа.

Резюме

Хранилища данных - это усовершенствованные решения для хранения данных. Proto Datastore использует прото-буферы и обеспечивает безопасность типов. Protobufs предназначены для сериализации и десериализации данных. Поскольку у него нет стабильной версии, подумайте дважды, прежде чем использовать его в приложениях. . Так что попробуйте ...

Спасибо за чтение…

Ресурсы

Еще статьи об Android