当前位置: 首页 > news >正文

DataStore入门及在项目中的使用

首先给个官网的的地址:应用架构:数据层 - DataStore - Android 开发者  |  Android Developers

小伙伴们可以直接看官网的资料,本篇文章是对官网的部分细节进行补充

一、为什么要使用DataStore 代替SharedPreferences

SharedPreferences:

  • DataStore出现之前,我们用的最多的存储方式毫无疑问是SP,其使用方式简单、易用,广受好评。然而google对SP的定义为轻量级存储,如果存储的数据少,使用起来没有任何问题,当需要存储数据比较多时,SP可能会导致以下问题:
  • 1. SP第一次加载数据时需要全量加载,当数据量大时可能会阻塞UI线程造成卡顿;
  • 2. SP读写文件不是类型安全的,且没有发出错误信号的机制,缺少事务性API;
  • 3. commit() / apply()操作可能会造成ANR问题;
  • commit()是同步提交,会在UI主线程中直接执行IO操作,当写入操作耗时比较长时就会导致UI线程被阻塞,进而产生ANR;apply()虽然是异步提交,但异步写入磁盘时,如果执行了Activity / Service中的onStop()方法,那么一样会同步等待SP写入完毕,等待时间过长时也会引起ANR问题。

DataStore:

  • DataStore基于事务方式处理数据更新。

  • DataStore基于Kotlin Flow存取数据,默认在Dispatchers.IO里异步操作,避免阻塞UI线程,且在读取数据时能对发生的Exception进行处理。

  • 不提供apply()、commit()存留数据的方法。

  • 支持SP一次性自动迁移至DataStore中

总结:SharedPreferences卡进程,DataStore不卡进程

二、如何使用

  1. 添加依赖,在build.grade(:app)中添加:
    implementation("androidx.datastore:datastore-preferences:1.0.0")
    
  2. 创建 Preferences DataStore
    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>
  3. 使用相应的键类型函数为需要存储在 DataStore<Preferences> 实例中的每个值定义一个键。例如,如需为 int 值定义一个键,请使用 intPreferencesKey()。通常我们项目中需要存储类似userId,userName类似字段,我以它们两个举例说明:

    private val USER_ID = intPreferencesKey("userId")
    private val USER_NAME = stringPreferencesKey("userName")
  4. 存入数据: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}}
  5. 读取数据:(我直接取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()
    }
  6. 如果是在Activity中可以直接使用lifecycleScope

    lifecycleScope.launch {getUserId()
    }
  7. 如果想在整个应用中随时调用,不跟随某个组件的生命周期,可以在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随时存储和读取数据啦

  8. 我们不想读取和存储数据是异步操作,比如我们的网络请求一header里开始就需要userID和username判断用户是否登录,我们可以使用runBlocking阻塞进程

            runBlocking {//此处取Flow都是取第一个值,可以写两个取值操作,DataStoreUtil.getUserId()DataStoreUtil. getUserName()//如果是没有调用flow.first()方法,无法取到username,可以把取值放在不同协程中,Flow就不会相互干扰了
    //            launch {
    //                getUserId()
    //            }
    //            launch {
    //                getUserName()
    //            }}
    
  9. 附上代码地址:GitHub - scYao/DataStoreDmeo: DataStore Demo

http://www.lryc.cn/news/68206.html

相关文章:

  • 用Python爬取中国各省GDP数据
  • 深度学习-第T5周——运动鞋品牌识别
  • 自媒体的孔雀效应:插根鸡毛还是专业才华?
  • Linux系统优化
  • Java笔记_22(反射和动态代理)
  • 前端web入门-HTML-day01
  • 创建一个Go项目
  • 从 Spring 的创建到 Bean 对象的存储、读取
  • 【一文吃透归并排序】基本归并·原地归并·自然归并 C++
  • 读《Spring Boot 3核心技术与最佳实践》有感
  • 板子短路了?
  • 一行代码绘制高分SCI限制立方图
  • spring 容器结构/机制debug分析--Spring 学习的核心内容和几个重要概念--IOC 的开发模式--综合解图
  • excel实战小测第四
  • 什么是SpringBoot自动配置
  • 基于IC5000烧录器使用winIDEA烧写+调试程序(S32K324的软件烧写与调试)
  • 新手开始学【网络安全】要怎么入门?
  • Linux指令 快捷键
  • Testing and fault tolerence考试要点
  • 记一次springboot项目漏洞挖掘
  • R语言 | 数据框
  • 基于SpringBoot的招生管理系统的设计与实现
  • Oracle Profile详解
  • r语言tidyverse教程:5 字符串处理stringr
  • 知识变现海哥:知识变现的本质就是卖
  • jdbc和druid和mybatis之间的关系
  • 云原生Istio案例实战
  • 解读赛力斯年报:华为智选车的B面
  • 互联网内卷严重?你咋不看看其他行业呢?无非是三十晚上无月亮,大家都一样
  • CompletableFuture异步任务编排使用