You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Proto DataStore保存对象列表?含Tag类实现疑问

当然支持用Proto DataStore保存对象列表啦!我来一步步给你讲清楚具体怎么做,从定义proto文件到实现数据操作的全流程都给你列出来,完全适配你自己的Tag数据类。

步骤1:定义Protocol Buffers消息类型

Proto DataStore是基于Protocol Buffers(简称Protobuf)的,所以首先得先定义对应的proto消息结构,用来映射你的Tag列表。

  1. 在你的Android项目里创建src/main/proto目录(如果没有的话),然后新建一个tag.proto文件。
  2. 写入以下内容:
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代码。

  1. 在项目根目录的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
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 15:32:58