• 一文了解DataStore(Preferences)


    前言

    1. 本篇主要介绍DataStore,包含介绍,使用等。
    2. 本篇会介绍DataStore两种实现Preferences DataStore(主要介绍)和Proto DataStore(后续介绍)。
    3. 本篇也会介绍到DataStore和SharedPreferences的不同之处,以及如何进行迁移。

    简介

    • 首先,DataStore是Jetpack一部分,是一种数据存储解决方案。
    • 其次,DataStore使用协程及flow以异步、一致的方式实现数据的存储。
    • 最后是DataStore的实现,分为Preferences DataStore和Proto DataStore:
      • Preferences DataStore 类似于SharedPreferences,键值对存储,本篇的主要介绍。
      • Proto DataStore 将数据作为自定义数据类型的实例进行存储,基于Google protobuf实现。

    DataStore和SharedPreferences(SP)

    • SP存在的问题:
      • 内存浪费问题,加载的数据会一直存在在内存中。
      • get方法可能会阻塞主线程。
      • apply方法虽然为异步,也可能会发生ANR。
      • SP也无法保证类型安全。
      • SP不支持跨进程。
    • DataStore的特点:
      • 基于协程和Flow实现,保证了主线程的安全性。
      • 以事务的方式进行处理,保证了操作的原子性、一致性、隔离性及持久性。
      • Preferences DataStore可以支持SP的迁移,保证数据的完整性。
    • 说明:
      • 此处只是列出SP存在的问题,并没有SP一无是处的的说法,DataStore在SP的基础上解决了不少的问题,但是也没有说SP存在的问题已经全部解决了。
      • 至少,DataStore在SP的基础上解决了如类型安全、阻塞导致anr等问题,确实这方面优于SP。

    Preferences DataStore

    1. 依赖引入及扩展

    • 依赖引入
    implementation 'androidx.datastore:datastore-preferences:1.0.0'
    
    • 1
    • 扩展属性,对Contex扩展属性,方便使用。
    val Context.dataStore by preferencesDataStore(name = "data_store")
    
    • 1

    2. 基本使用:

    编码
                //存储
                dataStore.edit { edit ->
                    edit[stringPreferencesKey("data")] = "123456"
                }
                //读取
               val data =  dataStore.data.first()[stringPreferencesKey("data")]
                Log.d(TAG.TAG,"data is $data")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    日志
    2022-08-04 14:38:15.606 13419-13445/edu.test.demo D/Test-TAG: data is 123456
    
    • 1
    分析:
    • 一眼看起来貌似和SP区别也不大,事实上使用起来区别也确实不大。
    • 区别在于key值不再是String,而是Preferences.Key,当然这是存储string的key,存储别的类型key也不一样。
    • 有一点就是必须在协程中使用,因为edit方法是suspend方法,读取的时候data返回值为flow,操作起来也是在协程中。

    3. 更新:

    代码1(也就是再编辑一遍就覆盖了)如下:
      //存储
                dataStore.edit { edit ->
                    edit[stringPreferencesKey("data")] = "123456"
                }
    
                //读取
               val data =  dataStore.data.first()[stringPreferencesKey("data")]
                Log.d(TAG.TAG,"data is $data")
    
                dataStore.edit { edit ->
                    edit[stringPreferencesKey("data")] = "123456789"
                }
    
                Log.d(TAG.TAG,"data is ${ dataStore.data.first()[stringPreferencesKey("data")]}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    日志如下:
    2022-08-04 14:44:25.651 13552-13579/edu.test.demo D/Test-TAG: data is 123456
    2022-08-04 14:44:25.657 13552-13579/edu.test.demo D/Test-TAG: data is 123456789
    
    • 1
    • 2
    代码2 调用update
     			 //存储
                dataStore.edit { edit ->
                    edit[stringPreferencesKey("data")] = "123456"
                }
    
                //读取
               val data =  dataStore.data.first()[stringPreferencesKey("data")]
                Log.d(TAG.TAG,"data is $data")
    
                dataStore.updateData {
                    val mutablePreference = it.toMutablePreferences()
                    mutablePreference[stringPreferencesKey("data")] = "123456789"
                    mutablePreference.toPreferences()
                }
    
                Log.d(TAG.TAG,"data is ${ dataStore.data.first()[stringPreferencesKey("data")]}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    分析:
    • 修改和SP也没有太大的却别,我们可以直接edit覆盖,也可以update。

    3. DataStore支持的存储类型:

    DataStore支持的存储类型从key上就可以看出,主要有七种,key类型以及调用方法如下,一眼就能看出来,就不一一
    解释了:
    
    • 1
    • 2
    • Preferences.Key intPreferencesKey
    • Preferences.Key doublePreferencesKey
    • Preferences.Key stringPreferencesKey
    • Preferences.Key booleanPreferencesKey
    • Preferences.Key floatPreferencesKey
    • Preferences.Key longPreferencesKey
    • Preferences.Key stringSetPreferencesKey

    4. SP到DataStore的迁移

    迁移编码:
    • 主要是在扩展进行迁移,传入sp的文件名。
    val Context.dataStore : DataStore<Preferences> by preferencesDataStore(name = "dataStore_setting",
        produceMigrations = { context ->
            listOf( SharedPreferencesMigration(context, "sp_data"))
        })
    
    • 1
    • 2
    • 3
    • 4

    迁移之前我们可以看下sp文件,位置为data/data/包名/shared_prefs/sp文件名:
    sp文件
    迁移之后,sp文件被删除,datastore文件出现,如下:
    sp迁移datastore之后文件

    验证编码:
      val data = dataStore.data.first()[stringPreferencesKey("mydata")]
               Log.d(TAG.TAG,"sp->datastore,直接读取:$data")
    
    • 1
    • 2
    日志如下:
    2022-08-04 15:22:24.062 14131-14157/edu.test.demo D/Test-TAG: sp->datastore,直接读取:mydata123456
    
    • 1
    分析:
    • 对比可以看出,迁移之后sp文件被删除,出现datastore文件。
    • 编码验证说明已经迁移成功,sp之前存储的值,我们在datastore直接读取了出来。
    • 只有在我们使用dataStore.data.first()的时候,才会进行文件的迁移。

    总结

    • 本篇主要介绍了DataStore的实现分类。
    • 本篇也介绍了DataStore在sp的基础上做了那些优化。
    • 介绍了DataStore的使用,支持数据类型,以及SP到DataStore的迁移。
  • 相关阅读:
    记录一次Maven依赖传递,模块之间依赖版本不一致问题
    使用内网穿透本地MariaDB数据库,并实现在公网环境下使用navicat图形化工具
    golang之map并发访问
    麒麟操作系统使用dconf配置环境变量记录
    【C语言】字符串函数
    剑指 Offer 03. 数组中重复的数字
    【寸铁的刷题笔记】图论、bfs、dfs
    Xgboost系列-XGB实际参数调优指南附源码
    MySQL基础篇
    用visa进行仪表通信
  • 原文地址:https://blog.csdn.net/jinjin10086/article/details/126158169