Jetpack DataStore 你总要了解一下吧?

目录

一、DataStore 介绍

Preferences DataStore 和 Proto DataStore

二、Preferences DataStore

2.1 添加依赖

2.2 使用 Preferences DataStore 存储键值对

2.2.1 创建 DataStore

2.2.1 DataStore 写入数据

2.2.3 DataStore 读取数据

三、Proto DataStore

3.1 定义架构

3.2 创建 Proto DataStore

四、相关链接


一、DataStore 介绍

        DataStore 是 Android Jetpack 中的一个组件,它是一个数据存储的解决方案,跟 SharedPreferences 一样,采用key-value形式存储。

        DataStore 保证原子性,一致性,隔离性,持久性。尤其是,它解决了 SharedPreferences API 的设计缺陷。

        Jetpack DataStore 是经过改进的新版数据存储解决方案,旨在取代 SharedPreferences,让应用能够以异步、事务方式存储数据。

注意:DataStore 比较适合小数据和简单操作,并且无法局部的更新数据。如果你需要支持大型或复杂的数据集、部分更新或引用完整性,请考虑使用 Room 而不是 DataStore。

Preferences DataStore 和 Proto DataStore

  • Preferences DataStore:与SharedPreferences类似,通过键值对存储数据,此实现不需要预定义模式,也不提供类型安全。

  • Proto DataStore:通过Protocol-Buffers定义存储数据类型以及结构,保证类型安全。

        本文重点了解Preferences DataStore。

二、Preferences DataStore

        与SharedPreferences类似,通过键值对存储数据,此实现不需要预定义模式,也不提供类型安全。

2.1 添加依赖

        在你项目的app_module对应的build.gradle中添加如下依赖:

dependencies {
    //Typed DataStore (Typed API surface, such as Proto)
    implementation "androidx.datastore:datastore:1.0.0"
//    //可选 - RxJava2 support
//    implementation "androidx.datastore:datastore-rxjava2:1.0.0"
//    //可选 - RxJava3 support
    implementation "androidx.datastore:datastore-rxjava3:1.0.0"
    
    //Preferences DataStore (SharedPreferences like APIs)
    implementation "androidx.datastore:datastore-preferences:1.0.0"
//    // 可选 - RxJava2 support
//    implementation "androidx.datastore:datastore-preferences-rxjava2:1.0.0"
//    // 可选 - RxJava3 support
    implementation "androidx.datastore:datastore-preferences-rxjava3:1.0.0"
}

2.2 使用 Preferences DataStore 存储键值对

        首先看看 DataStore 源码,DataStore 是一个接口。

package androidx.datastore.core

import kotlinx.coroutines.flow.Flow
import java.io.IOException

/**
 * DataStore数据存储提供了一种安全、持久的方式来存储少量数据,如 preferences 和应用程序状态。
 * 数据存储提供了ACID保证。它是线程安全的,并且不阻塞。特别是,它解决了SharedReferences API的这些设计缺陷:
 * 1. Synchronous API encourages StrictMode violations
 * 2. apply() and commit() have no mechanism of signalling errors
 * 3. apply() will block the UI thread on fsync()
 * 4. Not durable – it can returns state that is not yet persisted
 * 5. No consistency or transactional semantics
 * 6. Throws runtime exception on parsing errors
 * 7. Exposes mutable references to its internal state
 */
public interface DataStore<T> {
    public val data: Flow<T>

    public suspend fun updateData(transform: suspend (t: T) -> T): T
}

以上可以看出 DataStore 是基于 协程 和 Flow 实现的。

  • data 是一个 Flow 对象。

  • updateData() 用于更新对象。

        并且查看 DataStore 的其他相关源码你会发现他们都是基于Kotlin语言开发。Google 对于推 Kotlin 那是相当执着。

2.2.1 创建 DataStore

  • 使用 preferencesDataStore(Kotlin) 创建Datastore<Preferences> 的实例。

  • 如果你使用 RxJava,要使用 RxPreferenceDataStoreBuilder。

        必需的 name 参数是 Preferences DataStore 的名称。

        这里我们使用的是RxJava:

        RxDataStore<Preferences> dataStore =
                new RxPreferenceDataStoreBuilder(this, /*name=*/ "datastore_sc").build();
        //创建使用的key
        Preferences.Key<String> nameKey = PreferencesKeys.stringKey("name");
        Preferences.Key<Integer> ageKey = PreferencesKeys.intKey("age");

        默认路径:/data/data/com.scc.datastorage/files/datastore/datastore_sc.preferences_pb

        这里创建了两个key,分别是 String 类型和 Int 类型。

2.2.1 DataStore 写入数据

    //关于 nameKey 和 ageKey 请看上面代码。
    putString(nameKey, "name-Scc");
    putInteger(ageKey, 25);    
    
    //2022/1/25 功能:存入String类型的数据
    private void putString(Preferences.Key<String> nameKey, String value) {
        dataStore.updateDataAsync(new Function<Preferences, Single<Preferences>>() {
            @Override
            public Single<Preferences> apply(Preferences preferences) throws Throwable {
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set(nameKey, value);
                return Single.just(mutablePreferences);
            }
        });
    }
    //2022/1/25 功能:存入Integer类型的数据
    private void putInteger(Preferences.Key<Integer> ageKey, Integer value) {
        dataStore.updateDataAsync(new Function<Preferences, Single<Preferences>>() {
            @Override
            public Single<Preferences> apply(Preferences preferences) throws Throwable {
                MutablePreferences mutablePreferences = preferences.toMutablePreferences();
                mutablePreferences.set(ageKey, value);
                return Single.just(mutablePreferences);
            }
        });
    }

        这里写入的两种类型,这样更加仿版理解和你写成自己的工具类,因为使用 DataStore 比较少实践少就不提供工具类了,以免误导大家。

2.2.3 DataStore 读取数据

    getString(nameKey);
    getInteger(ageKey);
    
    //2022/1/25 功能:获取String类型数据
    private void getString(Preferences.Key<String> nameKey) {
        Log.e("DataStore", nameKey.toString());
        Flowable<String> example = dataStore.data().map(new Function<Preferences, String>() {
            @Override
            public String apply(Preferences preferences) {
                Log.e("DataStore.apply", preferences.get(nameKey));
                return preferences.get(nameKey);
            }
        });
        Log.e("DataStore.Flowable", example.first("default").blockingGet());
    }
    //2022/1/25 功能:获取Integer类型数据
    private void getInteger(Preferences.Key<Integer> ageKey) {
        Log.e("DataStoreKey", ageKey.toString());
        Flowable<Integer> example = dataStore.data().map(new Function<Preferences, Integer>() {
            @Override
            public Integer apply(Preferences preferences) {
                Log.e("DataStore.apply", preferences.get(ageKey).intValue() + "");
                return preferences.get(ageKey);
            }
        });
        Log.e("DataStore.Flowable", example.first(12).blockingGet().toString());
    }

三、Proto DataStore

        通过Protocol-Buffers定义存储数据类型以及结构,保证类型安全。

        Proto DataStore 实现使用 DataStore 和 Protocol-Buffers 将类型化对象持久保存到磁盘。

什么是 Protocol-Buffers?

        Protocol-Buffers是谷歌的语言中立、平台中立、可扩展的机制,用于序列化结构化数据——比如XML,但更小、更快、更简单。您只需定义一次数据的结构化方式,然后就可以使用特殊生成的源代码,轻松地在各种数据流之间以及使用各种语言编写和读取结构化数据。

3.1 定义架构

        Proto DataStore 需要app/src/main/proto/目录中的 proto 文件中的预定义模式。此架构定义了您在 Proto DataStore 中持久保存的对象的类型。

syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.scc.datastorage.proto";
option java_outer_classname = "User";

message User{
  string name = 1;
  int32 age = 2;
}

.proto 文件以包声明开头,这有助于防止不同项目之间的命名冲突。

  • java_multiple_files:可以为每个生成的类生成一个单独的 .java 文件。

  • java_package:指定生成的类应该使用什么 Java 包名称。如果您没有明确指定,它只会匹配包声明给出的包名。

  • java_outer_classname:定义了类名。如果没有设置这个 options ,它将通过将文件名转换为大写驼峰式来生成。例如,默认情况下,“my_proto.proto”将使用“MyProto”作为包装类名称。

定义 message:

  • 可以使用许多标准的简单数据类型可用作字段类型,包括 bool、int32、float、double 和 string。

  • 还可以通过使用其他 message 类型作为字段类型来为你的消息添加进一步的结构。

        每个元素上的 "= 1"、"= 2" 标记标识该字段在二进制编码中使用的唯一 "tag"

        更多关于 的内容可以去官网找找 protobuf 语言指南

注意:存储对象的类是在编译时从 proto 文件中定义的message生成的。确保你 rebuild 你的项目。

3.2 创建 Proto DataStore

  • 1.定义一个实现 Serializer<T> 的类,其中 T 是 proto 文件中定义的类型。

  • 2.使用 dataStore 创建的属性委托来创建 DataStore<T> 的实例,其中 T 是 proto 文件中定义的类型。

        写到这里 proto 文件中定义的类无法生成,也尝试了很多办法,不知道什么情况。后续步骤可参照官网,其他方法和Preferences DataStore类似。就不占用篇幅了。

四、相关链接

官方文档 DataStore

        个人感觉 DataStore 还没有 SP 和 MMKV 好用,推荐使用 MMKV 毕竟上线好几年了,而且是大厂推出,相对稳定一些,有些个人自己实现了 SP 的功能,但是万一有 Bug 或者突然不继续维护了是不是就尴尬了。

猜你喜欢

转载自blog.csdn.net/g984160547/article/details/122730602