2
2
3
3
基于属性委托的 key-value 方式存储封装
4
4
5
- 可用于基本类型,对象,可基于LiveData监听状态,提供迁移数据方法。
6
-
7
5
### 使用
8
6
``` gradle
9
7
allprojects {
@@ -18,3 +16,199 @@ dependencies {
18
16
}
19
17
```
20
18
[ ![ ] ( https://jitpack.io/v/EspoirX/KvPref.svg )] ( https://jitpack.io/#EspoirX/KvPref )
19
+
20
+ key-value 方式的存储相信每个项目都会用,而使用需要包装,作用是统一操作,方便使用并且如果换框架什么的时候可以轻松替换。
21
+
22
+ KvPref 是利用 kotlin 属性委托封装的一个框架,跟其他很多类似的原理差不多,网上也有很多文章,所以这里主要是看看用法合不合你心意。
23
+
24
+ ## 用法
25
+ ### 1. 初始化
26
+ ``` kotlin
27
+ KvPrefModel .initKvPref(this , object : Serializer {
28
+ private val gson = Gson ()
29
+ override fun serializeToJson (value : Any? ): String? {
30
+ return gson.toJson(value)
31
+ }
32
+
33
+ override fun deserializeFromJson (json : String? , type : Type ): Any? {
34
+ return gson.fromJson(json, type);
35
+ }
36
+ })
37
+ ```
38
+ 调用 initKvPref 方法初始化,传入 Application,第二个参数是序列化和反序列化的接口,因为 KvPref 是支持存储对象的,而对象存储其实是以 json 字符串形式进行。所以需要
39
+ 序列化和反序列化,而具体实现通过 Serializer 接口暴露给业务,如上所示是用 Gson 实现,如果你没有存储对象的需求,则可以不传第二个参数。
40
+
41
+
42
+ ### 2. 创建具体的 key-value 实现
43
+ ``` kotlin
44
+ interface KvPrefProvider {
45
+ fun get (context : Context , name : String , mode : Int ): SharedPreferences
46
+ }
47
+ ```
48
+ key-value 的实现有很多种,比如原生的 SharedPreferences 和 mmkv 等,所以这里需求实现一个 KvPrefProvider 接口,告诉框架你的方式是什么。
49
+
50
+ 比如我用 SharedPreferences:
51
+ ``` kotlin
52
+ class DefKvPref : KvPrefProvider {
53
+ override fun get (context : Context , name : String , mode : Int ): SharedPreferences {
54
+ return context.getSharedPreferences(name, mode)
55
+ }
56
+ }
57
+ ```
58
+ 比如我用 mmkv:
59
+ ``` kotlin
60
+ class MmKvPref : KvPrefProvider {
61
+ override fun get (context : Context , name : String , mode : Int ): SharedPreferences {
62
+ if (MMKV .getRootDir().isNullOrEmpty()) {
63
+ MMKV .initialize(context)
64
+ }
65
+ return MMKV .mmkvWithID(name, MMKV .SINGLE_PROCESS_MODE ) as SharedPreferences
66
+ }
67
+ }
68
+ ```
69
+
70
+
71
+
72
+ ### 3. 创建存放 key-value 配置的类
73
+ 创建一个类,object 类型,使其继承 KvPrefModel,则完成创建。
74
+ ``` kotlin
75
+ object SpFileDemo : KvPrefModel(" spFileName" ) { .. . }
76
+ ```
77
+ KvPrefModel 有两个参数,第一个参数是 key-value 文件的文件名,第二个参数是 KvPrefProvider,即具体实现。文件名是必需要有的,
78
+ 而第二个参数可以不传,不传的话默认实现就是 SharedPreferences,如果你用的是 mmkv 你可以这样:
79
+ ``` kotlin
80
+ object SpFileDemo : KvPrefModel(" spFileName" , MmKvPref ()) { .. . }
81
+ ```
82
+
83
+
84
+ ### 4. 具体使用
85
+ ``` kotlin
86
+ object SpFileDemo : KvPrefModel(" spFileName" ) {
87
+ var people: People ? by objPrefNullable(People ().apply { age = 100 ;name = " 吃狗屎" })
88
+ var otherpeople: People by objPref()
89
+ var name: String by stringPref()
90
+ var otherName: String? by stringPrefNullable()
91
+ var age: Int by intPref()
92
+ var height: Long by longPref()
93
+ var weight: Float by floatPref()
94
+ var isGay: Boolean? by booleanPrefNullable(false , key = " 是否是变态" )
95
+ }
96
+
97
+ SpFileDemo .name = " 大妈蛋"
98
+ Log .i(" MainActivity" , " read = " + SpFileDemo .name)
99
+ ```
100
+ 如上,在 SpFileDemo 里面定义了一些值,在使用的时候,给值赋值就是在写 key-value,直接获取值,就是在读 key-value。
101
+
102
+ 每个值的类型对应这一个相应的 xxxPref() 方法,值的类型对应的就是读写 key-value 的具体类型,比如 stringPref
103
+ 就是对应 putString 和 getString。
104
+
105
+ 每个 xxxPref() 方法都有两种,一个是 xxxPref(),一个是 xxxPrefNullable,因为 kotlin 对 null 的检查是严格的,所以如果你
106
+ 使用的值可能是 null 的话,请用 xxxPrefNullable 方法,其他没区别。对象对应的是 objPref() 和 objPrefNullable()
107
+
108
+ ### 5. xxxPref() 方法
109
+ ``` kotlin
110
+ fun stringPref (
111
+ default : String = "",
112
+ key : String? = null,
113
+ keyUpperCase : Boolean = isKeyUpperCase,
114
+ synchronous : Boolean = isCommitProperties
115
+ )
116
+ ```
117
+ 下面看看 xxxPref() 方法可以做什么,这里用 stringPref 举例,其他方法一样。
118
+
119
+ 首先每个 xxxPref() 方法都有 4 个参数,default 代表是默认值,意思就不说了,大家都知道。
120
+ key 代表是存储的 key,默认为空,在空的时候,存储是真正的 key 取的是变量名,不为空的时候取的就是这个 key。
121
+ keyUpperCase 代表是否把 key 变成大写,默认 false。
122
+ synchronous 代表是使用 apply() 还是 commit(),false 代表是使用 apply(),默认 false。
123
+
124
+ ### 6. 兼容 Java 的用法
125
+ ``` kotlin
126
+ object SpFileDemoJava {
127
+ fun setPeople (people : People ) {
128
+ SpFileDemo .people = people
129
+ }
130
+
131
+ fun getPeople () = SpFileDemo .people
132
+ }
133
+ ```
134
+ 因为属性委托不能直接用在 Java 代码上,所以只能麻烦一点再包装一层,也还好把...
135
+
136
+
137
+ ### 7. 批量操作
138
+ 如果要同时操作 N 个 key-value,就需要批量操作,因为一个个来显得不好。批量操作相关的 API 有 4 个:
139
+ ``` kotlin
140
+ fun beginBulkEdit () //开始批量操作
141
+ fun applyBulkEdit () //apply 形式结束批量操作
142
+ fun commitBulkEdit () //commit 形式结束批量操作
143
+ fun cancelBulkEdit () //释放资源
144
+ ```
145
+
146
+ 用法举例:
147
+ ``` kotlin
148
+ SpFileDemo .beginBulkEdit()
149
+ SpFileDemo .name = " 小明"
150
+ SpFileDemo .age = 18
151
+ SpFileDemo .isGay = true
152
+ SpFileDemo .applyBulkEdit()
153
+ SpFileDemo .cancelBulkEdit()
154
+ ```
155
+
156
+ 可以看到代码比较模版,所以这里也提供了扩展函数去直接使用:
157
+ ``` kotlin
158
+ SpFileDemo .applyBulk {
159
+ name = " 小明"
160
+ age = 18
161
+ isGay = true
162
+ }
163
+ ```
164
+
165
+ ### 8. 数据迁移
166
+ KvPref 提供了数据迁移方法,支持其他实现 SharedPreferences 接口的 key-value 实现把数据迁移到 KvPref。
167
+ 举例:
168
+ ``` kotlin
169
+ class KvMigrateProvider : ContentProvider () {
170
+ override fun onCreate (): Boolean {
171
+ if (context != null && context is Application ) {
172
+ KvPrefModel .initKvPref(context as Application , object : Serializer {
173
+ private val gson = Gson ()
174
+ override fun serializeToJson (value : Any? ): String? {
175
+ return gson.toJson(value)
176
+ }
177
+
178
+ override fun deserializeFromJson (json : String? , type : Type ): Any? {
179
+ return gson.fromJson(json, type);
180
+ }
181
+ })
182
+ SpFileDemo .migrate(PreferenceManager .getDefaultSharedPreferences(context))
183
+ }
184
+ return true
185
+ }
186
+ // ...
187
+ ```
188
+
189
+ 为了尽早执行迁移逻辑,这里使用了 ContentProvider ,然后顺便把初始化也放里面,通过 migrate 方法完成数据迁移。
190
+
191
+ ### 9 . 其他 API
192
+ ```kotlin
193
+ fun remove (property : KProperty <* >, synchronous : Boolean = isCommitProperties)
194
+ fun getPrefKey (property : KProperty <* >): String?
195
+ fun getPrefName (property : KProperty <* >): String?
196
+ fun getAll ()
197
+ ```
198
+
199
+ remove 就是删除的意思,getPrefKey 是获取 key- value 的 key 值,getPrefName 是获取变量名,getAll 是获取全部数据。
200
+
201
+ 使用方式:
202
+ ```kotlin
203
+ SpFileDemo .remove(SpFileDemo ::name)
204
+ val prefKey = SpFileDemo .getPrefKey(SpFileDemo ::name)
205
+ val prefName = SpFileDemo .getPrefName(SpFileDemo ::name)
206
+ val map = SpFileDemo .getAll()
207
+ ```
208
+ 注意参数都是以双冒号的形式传进去的
209
+
210
+
211
+
212
+
213
+
214
+
0 commit comments