|
| 1 | +#DataStoreKTX |
| 2 | + |
| 3 | +English | [中文](README_ZH.md) |
| 4 | + |
| 5 | +[](https://www.jitpack.io/#DylanCaiCoding/DataStoreKTX-KTX) |
| 6 | +[](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 | +``` |
0 commit comments