在Android中本地存储一些简单类型的数据时候通常使用SharePreferences
,但是由于对异步操作支持不太好,所以在新的版本中提供了DataStore
进行数据存储。DataStore
有两个不同的实现,Datastore Preferences
和Proto Datastore
。这两种实现有以下区别:
为了能解决掉SharePreferences
所存在的弊端,这里只对Proto Datastore
的使用方式进行记录。
在实际使用中除了DataStore
的依赖还需要添加一些其它的依赖。
Protocol
的依赖,用于实现类型化安全
协程coroutines
的依赖,因为DataStore
使用了Flow
作为数据流处理
由于DataStore
需要在异步环境中使用,为了更好配合jetpack,需要添加一些ktx拓展库,如livedata-ktx
、viewmodel-ktx
、lifecycle-ktx
整体依赖配置如下:
plugins {
...
id "com.google.protobuf" version "0.8.12"
}
dependencies {
//android一些库的ktx拓展
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
//协程
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1'
implementation "androidx.datastore:datastore-core:1.0.0"
implementation "androidx.datastore:datastore:1.0.0"
implementation "com.google.protobuf:protobuf-javalite:3.14.0"
...
}
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'
}
}
// Generates the java Protobuf-lite code for the Protobufs in this project. See
// https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
// for more information.
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option 'lite'
}
}
}
}
}
需要在../app/src/main/
处创建一个proto
文件夹,该位置是proto
文件存储的默认位置,如果需要更改的话,可以参考Android上使用Protocol Buffer_Mr_Tony的专栏-CSDN博客进行修改。创建完该文件夹后,在proto
文件夹创建拓展名为.proto
的文件(或者.pb
)。其代码例子如下:
test.proto
syntax = "proto3";
option java_package = "com.example.application";
option java_multiple_files = true;
message Settings {
int32 example_counter = 1;
}
protocol buffer
的语法规则参考Language Guide (proto3) | Protocol Buffers | Google Developers。编写完后,进行build重新编译程序。会在app/build/generated/source/proto
下面生成由java_package
指定的文件夹,如com/example/application
,下面生成由message
指定的名字的Settings.java
文件(其它类型的文件和分类规则参考protocol buffer
官方文档)。
待重新build生成文件后开始编写相关的DataStore
代码了。其主要分为解析器Serializer
的创建、DataStore
的创建、DataStore
的读取、DataStore
的修改。其编写方式主要参考官方文档。如下:
object SettingsSerializer : Serializer<Settings> {
override val defaultValue: Settings = Settings.getDefaultInstance()
override suspend fun readFrom(input: InputStream): Settings {
try {
return Settings.parseFrom(input)
} catch (exception: InvalidProtocolBufferException) {
throw CorruptionException("Cannot read proto.", exception)
}
}
override suspend fun writeTo(
t: Settings,
output: OutputStream) = t.writeTo(output)
}
val Context.settingsDataStore: DataStore<Settings> by dataStore(
fileName = "settings.proto",
serializer = SettingsSerializer
)
读取方式如下:
val exampleCounterFlow: Flow<Int> = context.settingsDataStore.data
.map { settings ->
// The exampleCounter property is generated from the proto schema.
settings.exampleCounter
}
更新方式如下:
suspend fun incrementCounter() {
context.settingsDataStore.updateData { currentSettings ->
currentSettings.toBuilder()
.setExampleCounter(currentSettings.exampleCounter + 1)
.build()
}
}
由于DataStore
需要在异步环境中使用,所以尽量不要阻塞主线程,其具体使用方式如下,例如在Activity中使用
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch(context = Dispatchers.IO){
settingsDataStore.data.first()//读取方式
incrementCounter()//写入方式
}
}
使用过程中对Protocol
的注意事项参考以下帖子:
Android上使用Protocol Buffer_Mr_Tony的专栏-CSDN博客