建设微信网站的流程,wordpress用户权限设置,美食网站建设背景介绍,东华软件是外包公司吗首先给个官网的的地址#xff1a;应用架构#xff1a;数据层 - DataStore - Android 开发者 | Android Developers
小伙伴们可以直接看官网的资料#xff0c;本篇文章是对官网的部分细节进行补充
一、为什么要使用DataStore 代替SharedPreferences
SharedPreferences应用架构数据层 - DataStore - Android 开发者 | Android Developers
小伙伴们可以直接看官网的资料本篇文章是对官网的部分细节进行补充
一、为什么要使用DataStore 代替SharedPreferences
SharedPreferences
DataStore出现之前我们用的最多的存储方式毫无疑问是SP其使用方式简单、易用广受好评。然而google对SP的定义为轻量级存储如果存储的数据少使用起来没有任何问题当需要存储数据比较多时SP可能会导致以下问题1. SP第一次加载数据时需要全量加载当数据量大时可能会阻塞UI线程造成卡顿2. SP读写文件不是类型安全的且没有发出错误信号的机制缺少事务性API3. commit() / apply()操作可能会造成ANR问题commit()是同步提交会在UI主线程中直接执行IO操作当写入操作耗时比较长时就会导致UI线程被阻塞进而产生ANRapply()虽然是异步提交但异步写入磁盘时如果执行了Activity / Service中的onStop()方法那么一样会同步等待SP写入完毕等待时间过长时也会引起ANR问题。
DataStore: DataStore基于事务方式处理数据更新。 DataStore基于Kotlin Flow存取数据默认在Dispatchers.IO里异步操作避免阻塞UI线程且在读取数据时能对发生的Exception进行处理。 不提供apply()、commit()存留数据的方法。 支持SP一次性自动迁移至DataStore中
总结SharedPreferences卡进程,DataStore不卡进程
二、如何使用
添加依赖在build.grade(:app)中添加 implementation(androidx.datastore:datastore-preferences:1.0.0)创建 Preferences DataStore private val Context.mDataStore: DataStorePreferences 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*): DataStorePreferences 使用相应的键类型函数为需要存储在 DataStorePreferences 实例中的每个值定义一个键。例如如需为 int 值定义一个键请使用 intPreferencesKey()。通常我们项目中需要存储类似userIduserName类似字段我以它们两个举例说明 private val USER_ID intPreferencesKey(userId)
private val USER_NAME stringPreferencesKey(userName) 存入数据Preferences DataStore 提供了一个 edit() 函数用于以事务方式更新 DataStore 中的数据。该函数的 transform 参数接受代码块您可以在其中根据需要更新值。转换块中的所有代码均被视为单个事务。 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}} 读取数据:我直接取Flow的第一个值 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()
// }}附上代码地址GitHub - scYao/DataStoreDmeo: DataStore Demo