Skip to content

Commit dc32656

Browse files
Add README.md and README_ZH.md
1 parent bb657ea commit dc32656

File tree

2 files changed

+365
-0
lines changed

2 files changed

+365
-0
lines changed

README.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#DataStoreKTX
2+
3+
English | [中文](README_ZH.md)
4+
5+
[![](https://www.jitpack.io/v/DylanCaiCoding/MMKV-KTX.svg)](https://www.jitpack.io/#DylanCaiCoding/DataStoreKTX-KTX)
6+
[![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://github.com/DylanCaiCoding/DataStoreKTX/blob/master/LICENSE)
7+
8+
[Jetpack DataStore](https://developer.android.com/topic/libraries/architecture/datastore) is a data storage solution that uses Kotlin Coroutines or RxJava to store data in an asynchronous manner with consistent transaction methods. Its usage is different from other storage solutions such as SharedPreferences and MMKV, making it more special. Therefore, there are not many good DataStore encapsulations available online. I have done a lot of exploration and attempts and finally developed a very satisfactory set of usage methods, which I hope can help everyone.
9+
10+
## Features
11+
12+
- No need to create DataStore or RxDataStore objects;
13+
- Supports both Kotlin Coroutines and RxJava usage;
14+
- Uses property names as key names, eliminating the need to declare a large number of key name constants;
15+
- Ensures type safety and avoids exceptions caused by inconsistent types or key values.
16+
17+
## DataStore vs MMKV
18+
19+
Which one to choose between DataStore and MMKV? It is recommended to read [this article](https://juejin.cn/post/7112268981163016229). If you find the article too long, you can directly read the summary. As for the view of DataStore, it needs to be modified a little bit, because DataStore now supports not only Kotlin Coroutines, but also RxJava usage. Therefore, DataStore is also suitable for Java projects.
20+
21+
If you plan to use MMKV, you can use my other library [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX). If you choose to use DataStore, then this library is your best choice.
22+
23+
## Basic Usage
24+
25+
Add the following to the root `build.gradle` file:
26+
27+
```groovy
28+
allprojects {
29+
repositories {
30+
//...
31+
maven { url 'https://www.jitpack.io' }
32+
}
33+
}
34+
```
35+
36+
Add the following dependencies to the module's `build.gradle` file:
37+
38+
```groovy
39+
dependencies {
40+
implementation 'com.github.DylanCaiCoding.DataStoreKTX:datastore-ktx:1.0.0'
41+
// Optional
42+
implementation 'com.github.DylanCaiCoding.DataStoreKTX:datastore-rxjava2:1.0.0'
43+
implementation 'com.github.DylanCaiCoding.DataStoreKTX:datastore-rxjava3:1.0.0'
44+
}
45+
```
46+
47+
Inherit the `DataStoreOwner` class in a class, and then use the `by xxxxPreference()` function to delegate the property to `DataStore`. For example:
48+
49+
```kotlin
50+
object SettingsRepository : DataStoreOwner(name = "settings") {
51+
val counter by intPreference()
52+
val language by stringPreference(default = "zh")
53+
}
54+
```
55+
56+
If you already have a superclass that cannot be inherited, implement `IDataStoreOwner by DataStoreOwner(name)` instead, for example:
57+
58+
```kotlin
59+
object SettingsRepository : BaseRepository(), IDataStoreOwner by DataStoreOwner(name = "settings") {
60+
//...
61+
}
62+
```
63+
64+
**Make sure that the `name` used is not duplicated so that type safety can be 100% guaranteed!!!**
65+
66+
The following delegation functions that use the property name as the retrieval key value are supported:
67+
68+
- intPreference()
69+
- longPreference()
70+
- booleanPreference()
71+
- floatPreference()
72+
- doublePreference()
73+
- stringPreference()
74+
- stringSetPreference()
75+
76+
The `get()` function that calls this property reads the data by executing `dataStore.data.map {...}`, for example:
77+
78+
```kotlin
79+
// Call in coroutine
80+
val language = SettingsRepository.language.get()
81+
// val language = SettingsRepository.language.getOrDefault()
82+
```
83+
84+
The `set()` function that calls this property saves the data by executing `dataStore.edit {...}`, for example:
85+
86+
```kotlin
87+
// Call in coroutine
88+
SettingsRepository.counter.set(100)
89+
SettingsRepository.counter.set { (this ?: 0) + 1 }
90+
```
91+
92+
This property can also be used as `Flow` or `LiveData`. In this way, a notification callback is made each time the data changes, which can be used to update UI or to write streaming code. For example:
93+
94+
```kotlin
95+
SettingsRepository.counter.asLiveData()
96+
.observe(this) {
97+
tvCount.text = (it ?: 0).toString()
98+
}
99+
```
100+
101+
```kotlin
102+
SettingsRepository.counter.asFlow()
103+
.map { ... }
104+
```
105+
106+
## Adaptation to RxJava
107+
108+
By default, only Coroutine is supported. You can perform some simple adaptations to extend it to support RxJava. First, add the dependency `datastore-rxjava2` or `datastore-rxjava3` to `build.gradle`.
109+
110+
```groovy
111+
dependencies {
112+
// Optional
113+
implementation 'com.github.DylanCaiCoding.DataStoreKTX:datastore-rxjava2:1.0.0'
114+
implementation 'com.github.DylanCaiCoding.DataStoreKTX:datastore-rxjava3:1.0.0'
115+
}
116+
```
117+
118+
Then change the `DataStoreOwner` class to the `RxDataStoreOwner` class, and it will be adapted. It's recommended to add the `@JvmStatic` annotation to the property, which will make Java code calling this property more concise.
119+
120+
```kotlin
121+
object SettingsRepository : RxDataStoreOwner(name = "settings") {
122+
@JvmStatic
123+
val counter by intPreference()
124+
}
125+
```
126+
127+
The new `getAsync()` function call of this property reads the data by executing `rxDataStore.updateDataAsync(prefsIn -> ...)`, and the return value is `Single<T>`, for example:
128+
129+
```java
130+
SettingsRepository.getCounter().getAsync()
131+
.subscribe(counter -> {
132+
//...
133+
});
134+
```
135+
136+
The new `setAsync()` function call of this property writes the data by executing `rxDataStore.data().map(prefs -> ...)`, for example:
137+
138+
```java
139+
SettingsRepository.getCounter().setAsync(100);
140+
SettingsRepository.getCounter().setAsync((counter, prefsIn) -> counter + 1);
141+
```
142+
143+
It can also be used as a `Flowable`. In this way, a notification callback is made each time the data changes, which can be used to update UI or to write streaming code. For example:
144+
145+
```java
146+
SettingsRepository.getCounter().asFlowable()
147+
.subscribeOn(Schedulers.io())
148+
.observeOn(AndroidSchedulers.mainThread())
149+
.subscribe(counter -> tvCounter.setText(String.valueOf(counter)));
150+
```
151+
152+
Coroutine and RxJava usage can be used together, as long as it is the same property, and the read/write functions operate on the same data source.
153+
154+
## Update Log
155+
156+
[Releases](https://github.com/DylanCaiCoding/DataStoreKTX/releases)
157+
158+
## Other Libraries by the Author
159+
160+
| Library | Introduction |
161+
| ------------------------------------------------------------ |-------------------------------------|
162+
| [Longan](https://github.com/DylanCaiCoding/Longan) | Possibly the easiest-to-use Kotlin utility library |
163+
| [LoadingStateView](https://github.com/DylanCaiCoding/LoadingStateView) | Decoupling the title bar or view of loading, loading failure, no data, etc., supporting two-line code integration into the base class |
164+
| [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | The most comprehensive ViewBinding tool |
165+
| [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX) | The most flexible and easy-to-use MMKV tool |
166+
| [Tracker](https://github.com/DylanCaiCoding/Tracker) | A lightweight tracking framework based on Buzzvideo's view tree tracking idea |
167+
168+
## License
169+
170+
```
171+
Copyright (C) 2023. Dylan Cai
172+
173+
Licensed under the Apache License, Version 2.0 (the "License");
174+
you may not use this file except in compliance with the License.
175+
You may obtain a copy of the License at
176+
177+
http://www.apache.org/licenses/LICENSE-2.0
178+
179+
Unless required by applicable law or agreed to in writing, software
180+
distributed under the License is distributed on an "AS IS" BASIS,
181+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
182+
See the License for the specific language governing permissions and
183+
limitations under the License.
184+
```

README_ZH.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# DataStoreKTX
2+
3+
[English](README.md) | 中文
4+
5+
[![](https://www.jitpack.io/v/DylanCaiCoding/MMKV-KTX.svg)](https://www.jitpack.io/#DylanCaiCoding/DataStoreKTX-KTX)
6+
[![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://github.com/DylanCaiCoding/DataStoreKTX/blob/master/LICENSE)
7+
8+
[Jetpack DataStore](https://developer.android.com/topic/libraries/architecture/datastore) 是一种数据存储解决方案,由于使用了 Kotlin 协程或者 RxJava 以异步、一致的事务方式存储数据,用法相较于其它存储方案 (SharedPreferences、MMKV) 会更加特别,所以目前网上都没有什么比较好的 DataStore 封装。个人也做了很多摸索和尝试,终于封装出了一套非常满意的用法,希望能帮助到大家。
9+
10+
## Features
11+
12+
- 无需创建 DataStore 或 RxDataStore 对象;
13+
- 支持 Kotlin 协程和 RxJava 用法;
14+
- 用属性名作为键名,无需声明大量的键名常量;
15+
- 可以确保类型安全,避免类型或者 key 值不一致导致的异常;
16+
17+
## DataStore VS MMKV
18+
19+
DataStore 和 MMKV 到底该怎么选?建议看下[扔物线的文章](https://juejin.cn/post/7112268981163016229),如果觉得文章太长可以直接看总结。最后关于 DataStore 的观点在现在来看要做一点点修改,因为现在 DataStore 不是必须使用 Kotlin 协程了,还支持 RxJava 的用法,所以在 Java 项目也是适合用 DataStore 的。
20+
21+
如果你打算用 MMKV,可以使用个人的另一个库 [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX)。如果选择使用 DataStore,那么这个库就是你的最佳选择。
22+
23+
## 基础用法
24+
25+
在根目录的 `build.gradle` 添加:
26+
27+
```groovy
28+
allprojects {
29+
repositories {
30+
//...
31+
maven { url 'https://www.jitpack.io' }
32+
}
33+
}
34+
```
35+
36+
在模块的 `build.gradle` 添加依赖:
37+
38+
```groovy
39+
dependencies {
40+
implementation 'com.github.DylanCaiCoding.DataStoreKTX:datastore-ktx:1.0.0'
41+
}
42+
```
43+
44+
让一个类继承 `DataStoreOwner` 类,即可在该类使用 `by xxxxPreference()` 函数将属性委托给 `DataStore`,比如:
45+
46+
```kotlin
47+
object SettingsRepository : DataStoreOwner(name = "settings") {
48+
val counter by intPreference()
49+
val language by stringPreference(default = "zh")
50+
}
51+
```
52+
53+
如果已经有了父类没法继承,那就实现 `IDataStoreOwner by DataStoreOwner(name)`,比如:
54+
55+
```kotlin
56+
object SettingsRepository : BaseRepository(), IDataStoreOwner by DataStoreOwner(name = "settings") {
57+
// ...
58+
}
59+
```
60+
61+
**要确保使用过的 `name` 不重复,只有这样才能 100% 确保类型安全!!!**
62+
63+
支持使用以下类型的委托函数,会用属性名作为存取的 key 值:
64+
65+
- intPreference()
66+
- longPreference()
67+
- booleanPreference()
68+
- floatPreference()
69+
- doublePreference()
70+
- stringPreference()
71+
- stringSetPreference()
72+
73+
调用该属性的 `get()` 函数会执行 `dataStore.data.map {...}` 的读取数据,比如:
74+
75+
```kotlin
76+
// 需要在协程中调用
77+
val language = SettingsRepository.language.get()
78+
// val language = SettingsRepository.language.getOrDefault()
79+
```
80+
81+
调用该属性的 `set()` 函数会执行 `dataStore.edit {...}` 的保存数据,比如:
82+
83+
```kotlin
84+
// 需要在协程中调用
85+
SettingsRepository.counter.set(100)
86+
SettingsRepository.counter.set { (this ?: 0) + 1 }
87+
```
88+
89+
也可以作为 `Flow``LiveData` 使用,这样每当数据发生变化都会有通知回调,可以更新 UI 或流式编程。比如:
90+
91+
```kotlin
92+
SettingsRepository.counter.asLiveData()
93+
.observe(this) {
94+
tvCount.text = (it ?: 0).toString()
95+
}
96+
```
97+
98+
```kotlin
99+
SettingsRepository.counter.asFlow()
100+
.map { ... }
101+
```
102+
103+
## 适配 RxJava
104+
105+
默认只支持协程用法,可以做一些简单地适配扩展出 RxJava 用法。首先要在 `build.gradle` 添加 `datastore-rxjava2``datastore-rxjava3` 依赖。
106+
107+
```groovy
108+
dependencies {
109+
// 可选
110+
implementation 'com.github.DylanCaiCoding.DataStoreKTX:datastore-rxjava2:1.0.0'
111+
implementation 'com.github.DylanCaiCoding.DataStoreKTX:datastore-rxjava3:1.0.0'
112+
}
113+
```
114+
115+
然后把 `DataStoreOwner` 类改为 `RxDataStoreOwner` 类,这样就适配好了。建议给属性添加 `@JvmStatic` 注解,可以让调用该属性的 Java 代码会更加简洁。
116+
117+
```kotlin
118+
object SettingsRepository : RxDataStoreOwner(name = "settings") {
119+
@JvmStatic
120+
val counter by intPreference()
121+
}
122+
```
123+
124+
调用该属性新增的 `getAsync()` 函数会执行 `rxDataStore.updateDataAsync(prefsIn -> ...)` 的读取数据,返回值是 `Single<T>`,比如:
125+
126+
```java
127+
SettingsRepository.getCounter().getAsync()
128+
.subscribe(counter -> {
129+
// ...
130+
});
131+
```
132+
133+
调用该属性新增的 `setAsync()` 函数会执行 `rxDataStore.data().map(prefs -> ...)` 的读取数据,比如:
134+
135+
```java
136+
SettingsRepository.getCounter().setAsync(100);
137+
SettingsRepository.getCounter().setAsync((counter, prefsIn) -> counter + 1);
138+
```
139+
140+
也可以将作为 `Flowable` 使用,这样每当数据发生变化都会有通知回调,可以更新 UI 或流式编程。比如:
141+
142+
```java
143+
SettingsRepository.getCounter().asFlowable()
144+
.subscribeOn(Schedulers.io())
145+
.observeOn(AndroidSchedulers.mainThread())
146+
.subscribe(counter -> tvCounter.setText(String.valueOf(counter)));
147+
```
148+
149+
协程用法和 RxJava 用法可以混用,只要是同一个属性,存取函数的都是操作同一个数据源。
150+
151+
## 更新日志
152+
153+
[Releases](https://github.com/DylanCaiCoding/DataStoreKTX/releases)
154+
155+
## 作者其它的库
156+
157+
|| 简介 |
158+
| ------------------------------------------------------------ |-------------------------------------|
159+
| [Longan](https://github.com/DylanCaiCoding/Longan) | 可能是最好用的 Kotlin 工具库 |
160+
| [LoadingStateView](https://github.com/DylanCaiCoding/LoadingStateView) | 深度解耦标题栏或加载中、加载失败、无数据等视图,支持两行代码集成到基类 |
161+
| [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | 最全面的 ViewBinding 工具 |
162+
| [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX) | 最灵活易用的 MMKV 工具 |
163+
| [Tracker](https://github.com/DylanCaiCoding/Tracker) | 基于西瓜视频的视图树埋点思路实现的轻量级埋点框架 |
164+
165+
## License
166+
167+
```
168+
Copyright (C) 2023. Dylan Cai
169+
170+
Licensed under the Apache License, Version 2.0 (the "License");
171+
you may not use this file except in compliance with the License.
172+
You may obtain a copy of the License at
173+
174+
http://www.apache.org/licenses/LICENSE-2.0
175+
176+
Unless required by applicable law or agreed to in writing, software
177+
distributed under the License is distributed on an "AS IS" BASIS,
178+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
179+
See the License for the specific language governing permissions and
180+
limitations under the License.
181+
```

0 commit comments

Comments
 (0)