android KV存储三部曲之DataStore

379 阅读2分钟

Android DataStore

看一下谷歌的官方介绍

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

如果您当前在使用 SharedPreferences 存储数据,请考虑迁移到 DataStore。 作为SP的替代者,DataStore能更好的配合kotlin使用

Preferences DataStore 和 Proto DataStore

DataStore 提供两种不同的实现:Preferences DataStore 和 Proto DataStore。

  • Preferences DataStore 使用键存储和访问数据。此实现不需要预定义的架构,也不确保类型安全。
  • Proto DataStore 将数据作为自定义数据类型的实例进行存储。此实现要求您使用协议缓冲区来定义架构,但可以确保类型安全。

Preferences DataStore

用来存储简单的键值对。

//Kotlin中引入datastore

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

//创建一个工具类来使用
/**
 * Preferences DataStore的使用
 *
 * */

//通过属性委托的方式创建,这样只要是Context中就能用到
val Context.settingsDataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")

//创建工具类,单例模式
object SettingsPreferencesDataStore {

    //字段的key,需要使用stringPreferencesKey包装一下
    private val nameKey = stringPreferencesKey("name")

    /**
     * 保存数据 注意这里使用suspend挂起函数 操作存取datastore的值要放在协程中完成保证主线程的安全
     * */
    suspend fun putName(context: Context, name: String) {
        context.settingsDataStore.edit { setting ->
            setting[nameKey] = name
        }
    }

    /**
     * 获取数据
     * */
    suspend fun getName(context: Context): String {
        val nameFlow: Flow<String> = context.settingsDataStore.data.map { settings ->
            settings[nameKey] ?: ""
        }
        return nameFlow.first()
    }
}

//在avitivity中使用
GlobalScope.launch {
    SettingsPreferencesDataStore.putName(this@MainActivity,"数据datastore的测试")
}

GlobalScope.launch {
    var value = SettingsPreferencesDataStore.getName(this@MainActivity)
    Log.d("tag","value is $value")
}

//如果使用同步的方式 官方建议使用 block函数来调用
val exampleData = runBlocking { this@MainActivity.dataStore.data.first() }

Preferences DataStore

Proto DataStore 实现使用 DataStore 和协议缓冲区将类型化的对象保留在磁盘上。 主要是用来确保类型化的安全

//
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    //引入protobuf
    id "com.google.protobuf" version "0.8.12"
}


implementation  "com.google.protobuf:protobuf-javalite:3.14.0"

//build.gradle中添加支持
protobuf {
    protoc {
        if (osdetector.os == "osx") {
            artifact = 'com.google.protobuf:protoc:3.14.0:osx-x86_64'
        } else {
            artifact = 'com.google.protobuf:protoc:3.14.0'
        }
    }

    generateProtoTasks {
        all().each { task ->
            task.builtins {
                java {
                    option 'lite'
                }
            }
        }
    }
}

//看下proto类
//版本
syntax = "proto3";
//包名
option java_package = "com.example.myapplication";
option java_multiple_files = true;
//数据类 settings属性名
message Settings {
  //int属性
  int32 example_counter = 1;
}


//存值要放到挂起函数中使用
suspend fun saveValue() {
    settingsDataStore1.updateData {
        it.toBuilder()
            .setExampleCounter(2)
            .build()
    }
}

suspend fun readValue() {
    //使用collect读取内容
    settingsDataStore1.data.first()
}


image.png

总结 总体来看使用起来还是稍显麻烦,但是了解具体配置后也还可以。如果要替换项目里的sp的话,可以使用datastore或者是项目里使用了jetpack组件的话也可以使用。一般的话,还是推荐mmkv。原理的话不多深究。推荐下面这篇文章,写的很好。

Android性能优化 - 从SharedPreferences跨越到DataStore - 掘金 (juejin.cn)