Android DataStore 使用详解

2023-11-17

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/127358235
本文出自【赵彦军的博客】

概述

官方文档:https://developer.android.com/topic/libraries/architecture/datastore

Jetpack DataStore 是一种数据存储解决方案,允许您使用协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致的事务方式存储数据。

使用

添加依赖:

implementation "androidx.datastore:datastore-preferences:1.0.0"

定义dataStore

//定义DataStore
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "user_info")

//定义key 
val keyName = stringPreferencesKey("name")
val keyAge = intPreferencesKey("age")

保存数据:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.datastore.preferences.core.edit
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleScope.launch {
            saveData("zhaoyanjun", 18)
        }
    }

    //dataStore保存数据
    suspend fun saveData(name: String, age: Int) {
        dataStore.edit {
            it[keyName] = name //保存字符串
            it[keyAge] = age //保存int
        }
    }

}

获取数据

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
     
        lifecycleScope.launch {
            getData()
        }

    }

    //dataStore获取数据,collect 是一个挂起函数,所以会一直挂起,只要name的值发起变更,collect 就会回调
    suspend fun getData() {
        val nameFlow = dataStore.data.map {
            it[keyName]
        }
        nameFlow.collect { name ->
            Log.d("getData ", "name $name")
        }
    }
}

dataStore.data 是一个 Flow 对象,使用一个 collect 操作符 可以接受 值的变化,一旦值发生变化,collect { } 就会回调,可以实现数据驱动 UI 的效果。

DataStore 本地数据

DataStore 文件在 files/datastore/ 目录,完整路径是

/data/data/com.zyj.exoplayerdemo/files/datastore/user_info.preferences_pb

在这里插入图片描述

查看DataStore 文件

双击 user_info.preferences_pb 在 AS 里打开

在这里插入图片描述

发现是乱码。

点击右键把 user_info.preferences_pb 导出到桌面

在这里插入图片描述
在 mac appStore 下载安装 Protobuf Viewer

在这里插入图片描述

Protobuf Viewer 打开我们导出的 pb 文件

在这里插入图片描述

Key 的枚举

在文中我们用到了

stringPreferencesKey("name")
intPreferencesKey("age")

除此之外,DataStore 还提供了其他类型的 Key

@JvmName("intKey")
public fun intPreferencesKey(name: String): Preferences.Key<Int> = Preferences.Key(name)

@JvmName("doubleKey")
public fun doublePreferencesKey(name: String): Preferences.Key<Double> = Preferences.Key(name)

@JvmName("stringKey")
public fun stringPreferencesKey(name: String): Preferences.Key<String> = Preferences.Key(name)

@JvmName("booleanKey")
public fun booleanPreferencesKey(name: String): Preferences.Key<Boolean> = Preferences.Key(name)

@JvmName("floatKey")
public fun floatPreferencesKey(name: String): Preferences.Key<Float> = Preferences.Key(name)

@JvmName("longKey")
public fun longPreferencesKey(name: String): Preferences.Key<Long> = Preferences.Key(name)

@JvmName("stringSetKey")
public fun stringSetPreferencesKey(name: String): Preferences.Key<Set<String>> =
    Preferences.Key(name)

同步API

在上面的演示过程中,我们使用 Flowcollect { } 操作符 , 但是 collect { } 会一直处于挂起状态,只要值发生变化,我们就会收到通知,符合数据驱动 UI 的设计模式。

但是在现实开发中,我们往往需要一个同步 api , 仅仅获取当前一次值,我们只关注本次的值是什么,至于以后得值变化,我们不关心。DataStore 提供了 同步api 来供我们使用 。

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
  
        lifecycleScope.launch {
            //同步api
            val first = dataStore.data.first()
            val name = first[keyName]
            val age = first[keyAge]
            Log.d("getData ", "name $name")
            Log.d("getData ", "age $age")
        }
    }

如果是 pb 文件里面没有值,那么就会返回 null

com.zyj.exoplayerdemo D/getData: name null
com.zyj.exoplayerdemo D/getData: age null

所以我们可以把获取名字,封装成一个同步方法

suspend fun getNameData(): String? {
    val nameFlow = dataStore.data.map {
            it[keyName]
    }
    return nameFlow.first()
}

清除内容

清除某个key

val keyName = stringPreferencesKey("name")

suspend fun clear() {
        dataStore.edit {
            it.remove(keyName)
        }
}

清除所有值

   suspend fun clear() {
        dataStore.edit {
            it.clear()
        }
    }

包含key

suspend fun contains() {
     dataStore.edit {
        //是否包含某个key
        var result =  it.contains(keyName)
   }
}

SharedPreferences 数据迁移

如果你原来是用 SharedPreferences , 想换到 DataStore 上,DataStore 提供了一键迁移,就一行代码就搞定了。

val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
    name = "user_info",
    produceMigrations = { context ->
        listOf(SharedPreferencesMigration(context, "sp_file_name"))
    })

DataStore 源码

DataStore 是一个接口

public interface DataStore<T> {
    /**
     * Provides efficient, cached (when possible) access to the latest durably persisted state.
     * The flow will always either emit a value or throw an exception encountered when attempting
     * to read from disk. If an exception is encountered, collecting again will attempt to read the
     * data again.
     *
     * Do not layer a cache on top of this API: it will be be impossible to guarantee consistency.
     * Instead, use data.first() to access a single snapshot.
     *
     * @return a flow representing the current state of the data
     * @throws IOException when an exception is encountered when reading data
     */
    public val data: Flow<T>

    /**
     * Updates the data transactionally in an atomic read-modify-write operation. All operations
     * are serialized, and the transform itself is a coroutine so it can perform heavy work
     * such as RPCs.
     *
     * The coroutine completes when the data has been persisted durably to disk (after which
     * [data] will reflect the update). If the transform or write to disk fails, the
     * transaction is aborted and an exception is thrown.
     *
     * @return the snapshot returned by the transform
     * @throws IOException when an exception is encountered when writing data to disk
     * @throws Exception when thrown by the transform function
     */
    public suspend fun updateData(transform: suspend (t: T) -> T): T
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android DataStore 使用详解 的相关文章

随机推荐

  • 未来数据中心核心技术:RDMA在京东的应用

    近日 由京东IT资源服务部组织的未来数据中心核心技术研讨会活动 在京东成功举办 活动邀请了京东人工智能 大数据 云计算团队的多位研发总监 技术骨干人员一同参与 在研讨会上 大家针对目前很火的RDMA 高性能网络相关话题 展开深入讨论 特别是
  • 解决 ubuntu apt-get TAB 键不能自动补全

    Add Bash Completion In Debian ash completion is a useful tool for completion of file paths commands etc By default it is
  • Redis是怎么对缓存下手的

    文章目录 数据模型 1 字符串 String 2 哈希表 Hash 3 列表 List 4 集合 Set 5 有序集合 Sorted Set 内存存储 以下是一些常见的Redis概念 支持多种数据结构 1 字符串 2 哈希表 3 列表 4
  • 五、格式化namenode出错

    一 报错问题 ERROR conf Configuration error parsing conf yarn site xml com ctc wstx exc WstxParsingException Illegal processin
  • 修改磁盘的io调度算法的方法

    修改磁盘的io调度算法的方法 1 1 临时修改echo noop gt sys block sdb queue scheduler 1 2 永久方法grub中配置增加命令行参数elevator noop 但这个影响是全局的 并且针对所有磁盘
  • 在idea使用GitHub账号、Copilot异常

    登录GitHub显示这样的信息 Invalid authentication data Connection refused connect Failed to initiate the GitHub login process Pleas
  • MacOS Edge GPO via .plist file.

    I created a plist file with the name com microsoft Edge plist Note the name has to be exactly the same and it s case sen
  • vofuria的开发(5)替换原vuforia的茶壶模型、改为自己想要的模型AR model

    1 在基于android NDK开发的过程中 替换目标图片之后就是如何替换掉官方demo中给的茶壶模型 换成自己想要模型 如果对替换目标图片不了解的可以点击这里 2 在更换模型的过程中首先你要有一个 obj的文件 这个文件你可以去下载 也可
  • Python 的垃圾回收机制(GC-GarbageCollection)

    得益于Python的自动垃圾回收机制 在Python中创建对象时无须手动释放 这对开发者非常友好 让开发者无须关注低层内存管理 但如果对其垃圾回收机制不了解 很多时候写出的Python代码会非常低效 垃圾回收算法有很多 主要有 引用计数 标
  • 变参函数的学习

    定义 可变参数函数又称参数个数可变函数 也可以称为变参函数 int printf const char format 其中printf就为典型的变参函数 其中 参数可分为两部分 数目确定的固定参数和数目可变的可选参数 函数至少需要一个固定参
  • = 1.0.1ubuntu2.13)' is not installed' aria-label='The required dependency 'apt (>= 1.0.1ubuntu2.13)' is not installed'> The required dependency 'apt (>= 1.0.1ubuntu2.13)' is not installed

    使用Ubuntu系统的时候 系统提示升级 从14 04升级到16 04时 提示 The required dependency apt gt 1 0 1ubuntu2 13 is not installed 该提示指的是没有安装所需的依赖
  • Django实现教育平台---个人用户中心管理

    修改用户头像 django文件 上传 下面的html的样式省去 上传文件一定要定义enctype
  • ElasticSearch6.x 之IK 分词

    IK分词器介绍 elasticsearch analysis ik git地址 https github com medcl elasticsearch analysis ik 分词方式 Analyzer ik smart ik max w
  • pycharm 有些库(函数)没有代码提示的解决办法

    问题描述 如图 输入变量im 后没有关于第三方库相应的函数或其他提示 当然 此文档的前提是有相关的函数说明以及已有相关设置等 解决方案 python是动态强类型语言 IDE无法判断Image open Me jpg 的返回值类型 无法根据参
  • Git密钥配置

    一 下载并安装Git 官网下载地址点击这里 二 打开git bash 选择一个空文件夹 右键选择 Git Bash Here 三 配置密钥 在Git Bash界面输入git命令 初始化自己的用户名和邮箱 git config global
  • C# string类型(引用类型)

    C string类型 引用类型 2016年03月31日 10 34 45 阅读数 966 sing类型 引用类型 名称 CTS类型 说明 string System String Unicode字符串 string str1 hello s
  • Python教程:类的继承——深入理解继承的概念和用法

    Python教程 类的继承 深入理解继承的概念和用法 类的继承是面向对象编程中的重要概念 它允许我们定义一个新的类 并从现有的类中继承属性和方法 这种继承关系可以让我们在代码中实现代码重用 提高代码的可维护性和可扩展性 在本文中 我们将深入
  • k8s非高可用环境搭建

    k8s非高可用环境搭建 文章目录 k8s非高可用环境搭建 环境准备 集群信息 1 节点规划 2 修改hostname 3 添加hosts解析 4 调整系统配置 5 安装docker 部署kubernetes 1 安装kubernetes k
  • Python 一篇入门

    目录 Python 的简介与特点 Python支持多种编程风格 解释运行 跨平台 可扩展强 可嵌入 丰富的库 Python版本选择 Python开发环境搭建 认识Python解释器 快速入门 变量和赋值 动态类型 变量命名规则 认识 数字
  • Android DataStore 使用详解

    转载请标明出处 http blog csdn net zhaoyanjun6 article details 127358235 本文出自 赵彦军的博客 文章目录 概述 使用 DataStore 本地数据 查看DataStore 文件 Ke