赞
踩
首先给个官网的的地址:应用架构:数据层 - DataStore - Android 开发者 | Android Developers
小伙伴们可以直接看官网的资料,本篇文章是对官网的部分细节进行补充
SharedPreferences:
DataStore:
DataStore基于事务方式处理数据更新。
DataStore基于Kotlin Flow存取数据,默认在Dispatchers.IO里异步操作,避免阻塞UI线程,且在读取数据时能对发生的Exception进行处理。
不提供apply()、commit()存留数据的方法。
支持SP一次性自动迁移至DataStore中
总结:SharedPreferences卡进程,DataStore不卡进程
implementation("androidx.datastore:datastore-preferences:1.0.0")
- private val Context.mDataStore: DataStore<Preferences> by preferencesDataStore(name = "appData")
- private val mContext =MyApplication.mContext
使用属性委托来创建,方便访问,并且可以保留为单例,只需要传入一个数据库名称即可,点开preferencesDataStore查看源码可以看到,只需要一个name参数,其他参数都是非必填,当初看到这个Context.mDataStore写法对新手有点蒙,各位小伙伴可以了解一下属性委托再看这个代码,preferencesDataStore返回的是PreferenceDataStoreSingletonDelegate,它的getValue方法如下,“委托必须提供一个操作符函数 getValue(),该函数具有以下参数: thisRef —— 必须与 属性所有者 类型(对于扩展属性——指被扩展的类型)相同或者是其超类型。 property —— 必须是类型 KProperty<*> 或其超类型“。这样我们就知道为啥使用Context加扩展写法了,如果直接在Application这样有上下文Context的地方可以直接写mDataStore而不是Context.mDataStore
override fun getValue(thisRef: Context, property: KProperty<*>): DataStore<Preferences>
使用相应的键类型函数为需要存储在 DataStore<Preferences> 实例中的每个值定义一个键。例如,如需为 int 值定义一个键,请使用 intPreferencesKey()。通常我们项目中需要存储类似userId,userName类似字段,我以它们两个举例说明:
- private val USER_ID = intPreferencesKey("userId")
- private val USER_NAME = stringPreferencesKey("userName")
- private suspend fun setUserName(userName: String) {
- mContext.mDataStore.edit { settings ->
- settings[USER_NAME] = userName
- }
- }
-
- private suspend fun setUserId(userId: Int) {
- mContext.mDataStore.edit { settings ->
- settings[USER_ID] = userId
- }
- }
- private suspend fun getUserId() {
- mUserId = mDataStore.data.map { preferences ->
- preferences[USER_ID] ?: 0
- }.first()
- }
-
- private suspend fun getUserName() {
- mUserName = mDataStore.data.map { preferences ->
- preferences[USER_NAME] ?: "empty"
- }.first()
- }
如果是在Activity中可以直接使用lifecycleScope
- lifecycleScope.launch {
- getUserId()
- }
如果想在整个应用中随时调用,不跟随某个组件的生命周期,可以在Application中声明一个全局的协程作用域,注意释放
- override fun onCreate() {
- mApplicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
- mContext = applicationContext
- }
-
- companion object {
- var mContext: Context by Delegates.notNull()
- var mApplicationScope: CoroutineScope by Delegates.notNull()
- }
-
- override fun onLowMemory() {
- super.onLowMemory()
- mApplicationScope.cancel()
- }
这样我们可以使用mApplicationScope随时存储和读取数据啦
我们不想读取和存储数据是异步操作,比如我们的网络请求一header里开始就需要userID和username判断用户是否登录,我们可以使用runBlocking阻塞进程
- runBlocking {
- //此处取Flow都是取第一个值,可以写两个取值操作,
- DataStoreUtil.getUserId()
- DataStoreUtil. getUserName()
-
- //如果是没有调用flow.first()方法,无法取到username,可以把取值放在不同协程中,Flow就不会相互干扰了
- // launch {
- // getUserId()
- // }
- // launch {
- // getUserName()
- // }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。