前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DataStore快速上手

DataStore快速上手

作者头像
韦东锏
发布2021-09-29 15:17:48
8050
发布2021-09-29 15:17:48
举报
文章被收录于专栏:Android码农

背景

刚好新项目中有用好DataStore,整理了下快速上手方法,背景如下

  1. 官方的文档是过时的
  2. 网上介绍文档也是过时的
  3. 网上很多的分装,都不够完整,不能直接拿来用

本文是基于最新的1.0.0-alpha08版本,文章有现成的分装好的方法,可以直接拿来用,使用前,先介绍下DataStore的特性

Datastore的特性

  1. 不支持跨进程(本质是基于文件存储,跨进程硬要用也是有值的,不过结果可能会错误或者会崩溃)
  2. 强制使用协程suspend,从根本上避免在主线程调用(这点是我最喜欢的)
  3. 内部的存储,本质还是文件读写,不过有缓存机制,避免频繁io
  4. 存储的文件读取路径,是外部设置的,建议设置在内部路径下,这样不需要涉及任何权限申请,当然也可以设置在外部sd卡上,这样万一App卸载重装了,SP的内容不会丢失
  5. 性能比SP有很大的提升,内部使用protocol-buffers,比sp的xml的高效
  6. 还有一个proto DataStore,因为没有使用到,暂时不做介绍

使用的注意事项

1、文件的命名,后缀必须用preferences_pb,可以看下内部的代码

代码语言:javascript
复制
check(file.extension == PreferencesSerializer.fileExtension) {
"File extension for file: $file does not match required extension for" +
" Preferences file: ${PreferencesSerializer.fileExtension}"
}

2、存储的文件路径,建议使用内部存储,避免涉及权限申请,类似下面这个

3、类似之前的SP,如果是多个表格,需要使用多个实例,这里的例子,就一个全局的实例

DataStore实例封装和初始化

代码语言:javascript
复制
private const val DEFAULT_DATA_PATH = "DefaultSpDataPath.preferences_pb"

    /**
     * 默认的实例
     */
    private val defaultDataStore by lazy {
        PreferenceDataStoreFactory.create {
            val parentFile =
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                    BaseApplication.getApplication().dataDir
                } else {
                    BaseApplication.getApplication().filesDir
                }
            File(parentFile.absolutePath, DEFAULT_DATA_PATH)
        }
    }

如果要多个实例,就再调用PreferenceDataStoreFactory.create来创建,然后传入不同的file地址,实例要跟地址一一匹配

数据的读取

代码语言:javascript
复制
/**
 * 保存SP数据的工具类,所有的sp的操作,要统一调用这个方法
 */
object SpUtils {
    /**
     * 读取sp的值
     */
    suspend fun <T> readValue(key: String, default: T): T {
        val value = defaultDataStore.data.map { setting ->
            when (default) {
                is String -> {
                    setting[stringPreferencesKey(key)] ?: default
                }
                is Int -> {
                    setting[intPreferencesKey(key)] ?: default
                }
                is Long -> {
                    setting[longPreferencesKey(key)] ?: default
                }
                is Boolean -> {
                    setting[booleanPreferencesKey(key)] ?: default
                }
                is Float -> {
                    setting[floatPreferencesKey(key)] ?: default
                }
                is Double -> {
                    setting[doublePreferencesKey(key)] ?: default
                }
                else -> {
                    throw IllegalArgumentException("Illegal default type $default")
                }
            }
        }
        return value.first() as T
    }

这里默认值使用了泛型,一是为了确定返回的类型;二是DataStore返回的结果是可空的,必须有默认值相匹配

数据的保存

代码语言:javascript
复制
    /**
     * 保存sp的值
     */
    suspend fun <T> saveValue(key: String, value: T) {
        defaultDataStore.edit { setting ->
            when (value) {
                is String -> {
                    setting[stringPreferencesKey(key)] = value
                }
                is Int -> {
                    setting[intPreferencesKey(key)] = value
                }
                is Long -> {
                    setting[longPreferencesKey(key)] = value
                }
                is Boolean -> {
                    setting[booleanPreferencesKey(key)] = value
                }
                is Float -> {
                    setting[floatPreferencesKey(key)] = value
                }
                is Double -> {
                    setting[doublePreferencesKey(key)] = value
                }
            }
        }
    }

一些说明

  1. 这里仅支持基本类型的保存,跟SP一样,如果要保存Bean类型,考虑使用proto DataStore或者room
  2. 读取跟保存的方法,都是suspend方法,需要协程体内部调用的,其目的是为了避免在主线程调用(涉及文件读取,是个io的操作),如果有特特殊的场景,需要同步调用,可以如下处理
代码语言:javascript
复制
val result runBlocking {
androidId = SpUtils.readValue("androidId", "")
                    if (TextUtils.isEmpty(androidId)) {
                        androidId = UUID.randomUUID().toString()
                        SpUtils.saveValue("androidId", androidId)
                    }
                    androidId
                }

接下来,有空的话,就继续介绍DataStore内部实现,待续...

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android码农 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • Datastore的特性
  • 使用的注意事项
  • DataStore实例封装和初始化
  • 数据的读取
  • 数据的保存
    • 一些说明
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档