赞
踩
github blog
qq: 2383518170
wx: lzyprime
经过几番修改。对DataStore
的封装方式初步定下,虽然还是不满意,但已经是目前能想到的最好的方式。等有了新想法再改。
目前:
// key
val UserId = stringPreferencesKey("user_id")
// use:
val userId = DS[UserId] // 取值
DS[UserId] = "new user id" // 设值
// or delegate read and write:
var userId by UserId(defaultValue = "") // 需要设置属性为空时的默认值。userId: String
repo.login(userId)
userId = "new user id"
// or readOnly
val userId by UserId // 只读. userId: String?
if(!userId.isNullOrEmpty()) repo.login(userId)
DS
:
// DS:
@JvmInline
value class DSManager(private val dataStore: DataStore<Preferences>) : DataStore<Preferences> {
...
}
val DS: DSManager by lazy {
...}
提供了两套获取方式。一种是像map一样的访问风格。一种是靠属性委托的方式。运算符重载
, 属性委托
, 内联类(用于收缩函数范围)
记录一下是如何一步步混沌邪恶的。
当前DataStore 1.0.0
,目的是替代之前的SharedPreference
, 解决它的诸多问题。除了Preference简单的key-value
形式,还有protobuf
版本。但是感觉鸡肋,小数据key-value
就够了,大数据建议Room
处理数据库。所以介于中间的部分,或者真的需要类型化的,真的有吗?
DataStore
以Flow
的方式提供数据,所以跑在协程里,可以不阻塞UI。
DataStore
的接口非常简单,一个data
, 一个fun updateData
:
// T = Preferences
public interface DataStore<T> {
public val data: Flow<T>
public suspend fun updateData(transform: suspend (t: T) -> T): T
}
public suspend fun DataStore<Preferences>.edit(transform: suspend (MutablePreferences) -> Unit): Preferences {
return this.updateData {
it.toMutablePreferences().apply {
transform(this) } }
}
data: Flow<Preferences>
。 Preferences
可以看作是个Map<Preferences.Key<*>, Any>
。
同时为了数据修改方便,提供了个edit
的拓展函数,调用的就是updateData
函数。
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "datastore_name")
preferencesDataStore
只为Context
下的属性提供只读的委托:ReadOnlyProperty<Context, DataStore<Preferences>>
。
所以前边非要定成Context
的拓展属性,属性名不一定非是这个, val Context.DS by ...
也可以。
搞清楚kotlin的属性委托
和拓展属性
,就懂了这行代码。
preferencesDataStore
相当于创建了个fileDir/<datastore_name>.preferences_pb
的文件, 存数据。
public abstract class Preferences internal constructor() {
public class Key<T> internal constructor(public val name: String){
... }
}
//create:
val USER_ID = stringPreferencesKey("user_id")
val Guide = booleanPreferencesKey("guide")
都被加了internal
限制,所以在外边调不了构造。然后通过stringPreferencesKey(name: String)
等一系列函数,创建特定类型的Key
, 好处是限定了类型的范围,不会创出不支持类型的Key
, 比如Key<UserInfo>
,Key<List<*>>
。
同时通过Preferences.Key<T>
保证类型安全,明确存的是T
类型数据。而SharedPreference
, 可以冲掉之前的值类型:
SharedPreference.edit{
it["userId"] = 1
it["userId"] = "new user id"
}
// 取值 -------------
val userIdFlow: Flow<String> = context.dataStore.data.map {
preferences -><
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。