Jetpack DataStore 你总要了解一下吧?

简介: 一、DataStore 介绍 DataStore 是 Android Jetpack 中的一个组件,它是一个数据存储的解决方案,跟 SharedPreferences 一样,采用key-value形式存储。 DataStore 保证原子性,一致性,隔离性,持久性。尤其是,它解决了 SharedPreferences API 的设计缺陷。 Jetpack DataStore 是经过改进的新版数据存储解决方案,旨在取代 SharedPreferences,让应用能够以异步、事务方式存储数据。


一、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 的实例。


  • 如果你使用 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


微信图片_20220525134527.png


这里创建了两个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 比较少实践少就不提供工具类了,以免误导大家。


微信图片_20220525134612.png


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());
    }

微信图片_20220525134648.png


三、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 是 proto 文件中定义的类型。


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


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


四、相关链接


官方文档 DataStore


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


相关文章
|
XML 存储 JSON
Android Jetpack组件 DataStore的使用和简单封装
Android Jetpack组件 DataStore的使用和简单封装
839 0
Android Jetpack组件 DataStore的使用和简单封装
|
存储 XML 安全
Android Jetpack系列之DataStore
`Jetpack DataStore` 是一种改进的新数据存储解决方案,允许使用**协议缓冲区**存储键值对或类型化对象。`DataStore` **以异步、一致的事务方式存储数据,克服了 SharedPreferences(以下统称为SP)的一些缺点**。`DataStore`基于`Kotlin`协程和`Flow`实现,并且可以对`SP`数据进行迁移,旨在取代`SP`
572 0
|
存储 安全
Jetpack之DataStore解析
前言在正式讲解DataStore之前,我们先回顾下大家熟知的SharedPreferences(以下简称SP),众所周知SP有一些缺点,如调用getXXX()获取数据,可能会阻塞主线程;无法保证类型安全;加载的数据会一直留在内存中,浪费内存;apply方法无法获取到操作成功或失败的结果。SharedPreferences回顾getXXX()可能会阻塞主线程请看以下SP获取value值的使用代码: 
297 0
Jetpack之DataStore解析
|
存储 安全 API
Jetpack之DataStore使用
前言DataStore提供了一种安全且持久的方式来存储少量数据。它不支持部分更新:如果任何字段被修改,整个对象将被序列化并持久到磁盘。它是线程安全的,非阻塞的。特别是,它解决了SharedPreferences这些设计缺陷:同步API鼓励违反StrictModeapply和commit没有发出错误信号的机制apply将阻塞fsync上的UI线程不持久-它可以返回尚未持久的状态没有一致性或事务语义在
285 0
Jetpack之DataStore使用
DHL
|
存储 缓存 安全
[Google] 再见 SharedPreferences 拥抱 Jetpack DataStore
Google 新增加了一个新 Jetpack 的成员 DataStore,主要用来替换 SharedPreferences, DataStore 应该是开发者期待已久的库,DataStore 是基于 Flow 实现的,一种新的数据存储方案,它提供了两种实现方式
DHL
335 0
[Google] 再见 SharedPreferences 拥抱 Jetpack DataStore
|
7月前
|
存储 安全 Android开发
构建高效的Android应用:Kotlin与Jetpack的结合
【5月更文挑战第31天】 在移动开发的世界中,Android 平台因其开放性和广泛的用户基础而备受开发者青睐。随着技术的进步和用户需求的不断升级,开发一个高效、流畅且易于维护的 Android 应用变得愈发重要。本文将探讨如何通过结合现代编程语言 Kotlin 和 Android Jetpack 组件来提升 Android 应用的性能和可维护性。我们将深入分析 Kotlin 语言的优势,探索 Jetpack 组件的核心功能,并通过实例演示如何在实际项目中应用这些技术。
|
6月前
|
数据管理 API 数据库
探索Android Jetpack:现代安卓开发的利器
Android Jetpack是谷歌为简化和优化安卓应用开发而推出的一套高级组件库。本文深入探讨了Jetpack的主要构成及其在应用开发中的实际运用,展示了如何通过使用这些工具来提升开发效率和应用性能。
|
5月前
|
存储 数据库 Android开发
🔥Android Jetpack全解析!拥抱Google官方库,让你的开发之旅更加顺畅无阻!🚀
【7月更文挑战第28天】在Android开发中追求高效稳定的路径?Android Jetpack作为Google官方库集合,是你的理想选择。它包含多个独立又协同工作的库,覆盖UI到安全性等多个领域,旨在减少样板代码,提高开发效率与应用质量。Jetpack核心组件如LiveData、ViewModel、Room等简化了数据绑定、状态保存及数据库操作。引入Jetpack只需在`build.gradle`中添加依赖。例如,使用Room进行数据库操作变得异常简单,从定义实体到实现CRUD操作,一切尽在掌握之中。拥抱Jetpack,提升开发效率,构建高质量应用!
84 4
|
7月前
|
Java 数据库 Android开发
构建高效Android应用:Kotlin与Jetpack的完美结合
【5月更文挑战第28天】 在现代移动开发领域,Android平台以其广泛的用户基础和开放性受到开发者青睐。随着技术的不断进步,Kotlin语言以其简洁性和功能性成为Android开发的首选。而Android Jetpack组件则为开发者提供了一套高质量的设计架构、工具和UI组件,以简化应用程序的开发过程。本文将探讨如何利用Kotlin语言和Android Jetpack组件共同构建一个高效的Android应用程序,涵盖从语言特性到架构模式的全面分析,并提供具体的实践指导。
|
6月前
|
Android开发
Jetpack Compose: Hello Android
Jetpack Compose: Hello Android