如何使用Proto DataStore保存对象列表?含Tag类实现疑问
当然支持用Proto DataStore保存对象列表啦!我来一步步给你讲清楚具体怎么做,从定义proto文件到实现数据操作的全流程都给你列出来,完全适配你自己的Tag数据类。
步骤1:定义Protocol Buffers消息类型
Proto DataStore是基于Protocol Buffers(简称Protobuf)的,所以首先得先定义对应的proto消息结构,用来映射你的Tag列表。
- 在你的Android项目里创建
src/main/proto目录(如果没有的话),然后新建一个tag.proto文件。 - 写入以下内容:
syntax = "proto3"; // 映射你的Tag数据类,命名成ProtoTag避免和你自己的Tag类冲突 message ProtoTag { int32 id = 1; // 对应Kotlin的Int类型 string name = 2; // 对应Kotlin的String类型 } // 用来存储ProtoTag的列表 message TagList { repeated ProtoTag tags = 1; // repeated关键字表示这是一个列表 }
这里的repeated就是Protobuf用来定义列表类型的关键字,完全满足你存储多个Tag对象的需求。
步骤2:配置项目Gradle依赖
接下来要配置Gradle,让它能根据proto文件生成对应的Kotlin代码。
- 在项目根目录的
build.gradle(或者build.gradle.kts)里添加Protobuf插件:
plugins { id("com.android.application") version "your-android-plugin-version" apply false id("com.google.protobuf") version "0.9.4" apply false }
- 在app模块的
build.gradle(或build.gradle.kts)里添加DataStore依赖和Protobuf配置:
plugins { id("com.android.application") id("com.google.protobuf") } android { // ... 其他配置 sourceSets { main { proto { srcDir("src/main/proto") // 指定proto文件的目录 } } } } dependencies { // Proto DataStore依赖 implementation("androidx.datastore:datastore-proto:1.0.0") } protobuf { protoc { artifact = "com.google.protobuf:protoc:3.24.4" } // 生成Kotlin代码 generateProtoTasks { all().forEach { task -> task.builtins { register("kotlin") { option("lite") } } } } }
注意替换成你项目中对应的插件版本,同步Gradle后,就会自动生成ProtoTag和TagList的Kotlin类。
步骤3:创建Proto DataStore实例
现在创建一个单例的DataStore实例,方便全局调用:
import androidx.datastore.core.DataStore import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler import androidx.datastore.protobuf.InvalidProtocolBufferException import androidx.datastore.createDataStore object TagDataStore { // 创建DataStore实例,指定序列化器为自动生成的TagListSerializer private val Context.tagDataStore: DataStore<TagList> by createDataStore( fileName = "tags.pb", // 存储的文件名 serializer = TagListSerializer, corruptionHandler = ReplaceFileCorruptionHandler { // 如果文件损坏,返回一个空的TagList TagList.getDefaultInstance() } ) // 对外暴露的DataStore实例 val dataStore: DataStore<TagList> get() = ApplicationProvider.getApplicationContext<Context>().tagDataStore }
这里的TagListSerializer是自动生成的,不需要你自己写,Protobuf插件会帮你生成对应的序列化器。
步骤4:实现列表的增删改查操作
接下来我们需要把自动生成的ProtoTag和你自己的Tag数据类做转换,然后实现具体的操作函数。
首先写两个扩展函数,用来互相转换:
// 把ProtoTag转成自己的Tag数据类 fun ProtoTag.toTag(): Tag = Tag(id = this.id, name = this.name) // 把自己的Tag转成ProtoTag fun Tag.toProtoTag(): ProtoTag = ProtoTag.newBuilder() .setId(this.id) .setName(this.name) .build()
然后实现具体的操作(所有操作都要在挂起函数里,因为DataStore的操作是异步的):
import kotlinx.coroutines.flow.first // 获取所有Tag列表 suspend fun getTagList(): List<Tag> { return TagDataStore.dataStore.data.first().tagsList.map { it.toTag() } } // 保存整个Tag列表 suspend fun saveTagList(tags: List<Tag>) { TagDataStore.dataStore.updateData { currentList -> currentList.toBuilder() .clearTags() // 先清空现有列表 .addAllTags(tags.map { it.toProtoTag() }) // 添加新的列表 .build() } } // 添加单个Tag suspend fun addTag(tag: Tag) { TagDataStore.dataStore.updateData { currentList -> currentList.toBuilder() .addTags(tag.toProtoTag()) // 在现有列表末尾添加新Tag .build() } } // 根据ID删除Tag suspend fun deleteTag(tagId: Int) { TagDataStore.dataStore.updateData { currentList -> // 过滤掉要删除的Tag val filteredTags = currentList.tagsList.filter { it.id != tagId } currentList.toBuilder() .clearTags() .addAllTags(filteredTags) .build() } } // 根据ID更新Tag suspend fun updateTag(updatedTag: Tag) { TagDataStore.dataStore.updateData { currentList -> val updatedTags = currentList.tagsList.map { protoTag -> if (protoTag.id == updatedTag.id) { updatedTag.toProtoTag() } else { protoTag } } currentList.toBuilder() .clearTags() .addAllTags(updatedTags) .build() } }
注意事项
- 所有DataStore的操作都必须在协程中调用,比如在ViewModel里用
viewModelScope.launch,或者在Activity/Fragment里用lifecycleScope.launch。 - 如果你的
Tag类有更多字段,只需要在ProtoTag里添加对应的Protobuf字段即可,保持类型对应(比如Kotlin的Long对应Protobuf的int64,Boolean对应bool等)。 - 不要直接修改自动生成的Protobuf类,所有修改都要通过proto文件重新生成。
内容的提问来源于stack exchange,提问作者Guilherme Oliveira
相关产品推荐
相关产品推荐

