首页 > 其他分享 >KDataStore:一个简单易用的持久化方案

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

时间:2023-08-18 10:05:11浏览次数:40  
标签:github 持久 implementation 写入 kotlinx 易用 ms KDataStore

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:一个简单易用的持久化方案_数据_04

调用

当我们在 Activity 中使用 KDatStore 时:

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

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

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

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

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

RadioButton 处更新存值

KDataStore:一个简单易用的持久化方案_数据_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:一个简单易用的持久化方案_数据_08

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

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

6. 迁移

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

比如取自 SharedPreferences

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

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

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

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

7. 可选参数

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

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

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

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

8. 重置

全部重置代码如下

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

部分重置代码如下

Settings.isDarkMode.reset()

标签:github,持久,implementation,写入,kotlinx,易用,ms,KDataStore
From: https://blog.51cto.com/u_64214/7131911

相关文章

  • 关于Mybatis 和 Hibernate 持久层框架之间的区别
    首先,Mybatis和Hibernate都是ORM持久层框架不同点在于,MyBatis是半自动的,它需要开发人员自己手动编写SQL语句。一、MybatisMyBatis支持通过XML或注解的方式来配置需要运行的SQL语句,并且,最终由框架本身将Java对象和SQL语句映射生成最终执行的SQL,执行后,再将结果映射......
  • 「Note」数据结构方向 - 可持久化数据结构
    1.可持久化线段树1.1.介绍可持久化线段树一般用于解决区间第\(k\)小值的询问。首先考虑简化过的问题,区间\(\left[1,r\right]\)的第\(k\)小值。考虑用权值线段树(离散化或动态开点)来求\(k\)小值,接下来只需要解决区间的问题。可持久化线段树核心思想:每次插入值时保留......
  • Docker数据持久化与数据共享
    上篇文章的最后我们使用Docker部署了一个纯前端项目,但还有一个很重要的问题就是容器中产生的数据(比如log文件),容器一旦被删除,容器内的所有数据也就没有了,为了避免这个问题我们可以将数据存储到容器之外(比如宿主机),这样即使删除容器也不会丢失数据。一旦容器故障,我们可以重新创建一个......
  • 杭电23多校第九场Capoo on tree(二分+树链剖分+可持久化线段树)
    2023HDU多校9__Capooontree(二分+树链剖分+可持久化线段树)题目链接Solution\(Hint1\)考虑如何进行对某一相同点权的所有点进行点权\(+1\)操作,如果我们建立权值线段树,那只需要将权值为\(x\)的点并入权值\(x+1\)即可,但是这样就算我们建立以节点编号为版本的可持久化线段树,也是......
  • 什么是数据访问与持久化?
    在谈论Spring框架时,一个重要且深奥的主题是数据访问与持久化(DataAccessandPersistence)。在本篇博客中,我们将深入探讨数据访问与持久化的概念、原理以及在Spring中的应用。数据访问与持久化是指在应用程序中与数据存储交互的过程。它涉及到从数据库或其他数据存储中读取和写......
  • 数据存储与持久化的重要性
    在后端开发中,数据存储与持久化是至关重要的,它涉及将应用程序的数据保存在持久层,以确保数据的安全性和可靠性。不同的数据存储选项适用于不同的场景和需求。关系型数据库关系型数据库(如MySQL、PostgreSQL、Oracle)使用表格来存储数据,并通过关系(键值)将表格连接起来。这种结构有助于处......
  • 《高级程序员 面试攻略 》Kafka如何实现高吞吐量和持久性。
    Kafka是一个分布式流处理平台,它通过一些关键特性来实现高吞吐量和持久性。下面是Kafka实现这些特性的主要方法:1.分布式架构:Kafka是一个分布式系统,它通过将数据分布在多个节点上来实现高吞吐量。每个节点(称为KafkaBroker)负责处理一部分数据和请求。生产者和消费者可以同时......
  • Redis 持久化及集群架构
    1Redis持久化1.1持久化的概念和原因Redis持久化是指将Redis服务器中的数据保存到磁盘上,以便在服务器重启后可以重新加载数据。持久化是为了解决Redis内存数据库的数据丢失问题。持久化的原因有以下几点:数据安全:通过将数据保存到磁盘上,即使发生服务器故障或断电等情况......
  • pinia持久化存储插件-pinia-plugin-persistedstate
    pinia-plugin-persistedstate丰富的功能可以使PiniaStore的持久化更易配置:与vuex-persistedstate相似的API所有Store均可单独配置自定义storage和数据序列化恢复持久化数据前后的hook每个Store具有丰富的配置兼容Vue2和3无任何外部依赖安装使用你喜......
  • python - 将数据附加到 Pandas 全局数据框变量不会持久
    https://www.coder.work/article/5047954我正在尝试使用pandasdataframe全局变量。但是,当我尝试将数据框重新分配或附加到全局变量时,数据框是空的。任何帮助表示赞赏。importpandasaspddf=pd.DataFrame()defmy_func():globaldfd=pd.DataFrame()fo......