KDataStore:一个简单易用的持久化方案
  ETWZF7L1nsXD 2023年11月02日 26 0

1. 项目背景

安卓本地快捷存储方案如 SharedPreferences、MMKV、DataStore 都有明显的缺点,未能兼顾好安全、 性能、类型支持、和用法简易方便的程度,个人基于 DataStore, 做了一个新的方案 KDataStore。

https://github.com/ShawxingKwok/KDataStore

主要有以下优化:

  • 单例模式
  • 通过委托生成 key。
  • 采用 MutbaleStateFlow 即时观察、同步读写、异步写入磁盘。
  • 备份数据以处理异常。

在支持 IOS 之后会移到 Multiplatform 分组中。

2. 竞品对比


SharedPreferences

MMKV

DataStore

KDataStore

性能

启动: 2.5ms     

读取:耗时可忽略        

commit写入: 堵塞2.3ms        
apply写入: 耗时可忽略,但不知道是否成功异步写入磁盘。

启动: 2.3ms        

读写:耗时可忽略

都通过异步,故只测响应: 8.6ms

启动: 13.5ms
文件显著增加时影响不大,亦可先行在 
Application中异步启动来解决。       

读写:耗时可忽略

类型安全

除常见基本类型, String, Set<String> 外的类型支持


Parcelable

自定义
但需放在独立的 DataStore 中

Kt Serializable (包括常见存储类型)

自定义

读取异常

返回空的 HashMap, 即全部采用默认值

自行 catch 处理

启用备份文件

写入中遇 IOException

用未写入该数据的备份文件替换,且不再写入该数据。    
如用 
commit, 可通过返回的 false 获悉

 catch 不处理

记录,下次启动时从备份文件中更新

多进程

自行封装

支持

处于 1.1.0-alpha 阶段

在 DataStore 1.1.0 发布之后

多平台

不支持

支持

加密

自行封装

支持

自行封装

需自选加密协议,实现 cipher

额外优点


后台定时异步写入磁盘,ANR前一刻更新的数据不会丢失 


体积小,jar on Android side 仅 12.6 kb    

额外缺点


断电或者系统崩溃后容易丢失很多数据


比较新        

建模时只能使用 Kotlin, 调用时可以使用 Java。

以上测试结果采用 30 份 String 数据,机型魅族18s, 源码见 KDataStore.benchmark

关于其他地方的存储方案对比分析,绝大多数都有严重错误。官网相对准确,但也很片面。如想探究,建议自己测试并查阅源码。

3. 基础用法

KDataStore:一个简单易用的持久化方案_github

以切换主题的场景为例,使用 KDataStore 存储 Boolean 值代表当前主题

建模

单独分出一个 Android 模块, 常见命名为 settings

如果不考虑从 Java 文件中调用,下图中的 @JvmStatic 则是不需要的。

KDataStore:一个简单易用的持久化方案_数据_02

关于 KDSFlow

KDataStore:一个简单易用的持久化方案_ci_03

Android 上的 actual KDSFlow 实现

KDataStore:一个简单易用的持久化方案_ci_04

调用

当我们在 Activity 中使用 KDatStore 时:

  1. 在 Activity/BasicActivity 中观察Flow/LiveData,绑定主题。
  2. 选中的 RadioButton 会随用户点击自动变化,根据 isDarkMOde.value 设置起始状态即可,不用绑定。
  3. 在 RadioGroup 监听中更新存值。

KDataStore:一个简单易用的持久化方案_ci_05

在 Fragment 中观察 Flow 时建议采用 collectOnResume。其配置工作在下文有包括。

再看一下在 Compose 中的使用效果

KDataStore:一个简单易用的持久化方案_数据_06

RadioButton 处更新存值

KDataStore:一个简单易用的持久化方案_github_07

4. 配置

根目录

配置 build.gradle/build.gradle.kts 如下, 或参考 Github 上的 demo (其中有使用 version catalog)。

plugins{
    ...
    id 'org.jetbrains.kotlin.plugin.serialization' version "$version_kt" apply false
}

模块

plugins {
    ...
    id 'kotlinx-serialization'
}

dependencies {
    ...
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1' 
    implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1'
    implementation 'io.github.shawxingkwok:kt-util:1.0.0'
    implementation 'io.github.shawxingkwok:kdatastore:1.0.0'
}

调用方

view

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach{
    kotlinOptions.freeCompilerArgs += "-Xcontext-receivers"
}

dependencies {
    ...
    implementation 'io.github.shawxingkwok:android-util-view:1.0.0'
    implementation 'io.github.shawxingkwok:kdatastore:1.0.0'
    implementation project(':本地模型模块名称') // 或远程仓库
}

compose

dependencies{
    ...
    implementation 'io.github.shawxingkwok:kdatastore:1.0.0'
    implementation project(':本地模型模块名称') // 或远程仓库
}

如果该调用模块使用了 startup-runtime, 要注意在 dependencies 中包含 KDataStoreInitializer::class.java。

5. 类型支持

kotlinx.serialization 用法类似 Java Serializable, 但多平台,且速度快两倍多。被 Serializable 标记的 class, 基本类型,enumPairIntArrayList 的默认实现等等均可视为 Serializable。

KDataStore:一个简单易用的持久化方案_github_08

  • Non-null 时需声明默认值。
  • Nullable 时默认值被限制为 null。
  • 自定义时需实现与 Kt Serializable 之间的相互转换。(convert/recover)

KDataStore:一个简单易用的持久化方案_ci_09

6. 迁移

类比下图格式(判断存在 -> 迁移 -> 删除)从其他存储仓库迁移过来。其中的 appContext 源自 KDataStore.

比如取自 SharedPreferences

KDataStore:一个简单易用的持久化方案_github_10

此外内置 delete, exist 两个函数辅助从 KDataStore 迁移到别处。

KDataStore:一个简单易用的持久化方案_github_11

警告以防止误用,并无异常风险。

7. 可选参数

KDataStore:一个简单易用的持久化方案_github_12

KDataStore:一个简单易用的持久化方案_ci_13

加密部分需从 Java 标准库或其他库中自选加密协议,实现 cipher。

加密会将启动时间提升一倍左右。Android 在 api 29 版本引入了沙盒机制,实现了数据隔离,脱离加密也相对安全。

8. 重置

全部重置代码如下

KDataStore:一个简单易用的持久化方案_数据_14

部分重置代码如下

Settings.isDarkMode.reset()
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  eHipUjOuzYYH   2023年12月07日   28   0   0 数据乐观锁redis
  jnZtF7Co41Wg   2023年12月09日   29   0   0 客户端服务端数据
ETWZF7L1nsXD