• 一文了解DataStore(Proto)


    前言

    1. 本篇主要介绍Proto DataStore的内容。
    2. 如果还不了解DataStore,请参考上篇一文了解DataStore(Preferences)
    3. 本篇会涉及到Protocol Buffers相关的内容,如果不太了解,可以查资料作以了解。

    准备工作

    1. 插件引入:

    plugins {
        id "com.google.protobuf" version "0.8.17"
    }
    
        protobuf {
            protoc {
                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'
                        }
                    }
                }
            }
    
        }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2. 依赖引入

        implementation 'androidx.datastore:datastore:1.0.0'
        implementation 'androidx.datastore:datastore-preferences:1.0.0'
        implementation  "androidx.datastore:datastore-core:1.0.0"
        implementation  "com.google.protobuf:protobuf-javalite:3.18.0"
    
    • 1
    • 2
    • 3
    • 4

    3. proto编写及编译

    • proto文件目录src/main/proto
    • proto内容如下:
    #固有的 使用proto3
    syntax = "proto3";
    # 固有   将edu.test.demo改为自己的包名
    option java_package = "edu.test.demo";
    option java_multiple_files = true;
    
    # 内容定义 UserPreferences 为类名
    # 字段格式为  类型 字段名 = 编号 ,注意此处编号需要唯一。
    message UserPreferences {
        string name = 1;
        int32 age = 2;
        float weight = 3;
        float tall = 4;
        int32 sex = 5;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 完成之后进行编译项目,即可生成相关的文件,生成文件以下目录:
      app/build/generated/source/proto/debug/包名/
      如下图所示:
      proto生成的文件

    4. 编写序列化类

    代码如下:
    object UserPreferencesSerializer:Serializer<UserPreferences> {
        override val defaultValue: UserPreferences
            get() = UserPreferences.getDefaultInstance()
    
        override suspend fun readFrom(input: InputStream): UserPreferences {
            try {
                return UserPreferences.parseFrom(input)
            } catch (exception: InvalidProtocolBufferException) {
                throw CorruptionException("Cannot read proto.", exception)
            }
        }
    
        override suspend fun writeTo(t: UserPreferences, output: OutputStream) {
            t.writeTo(output)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    其他补充:

    自定义编译生成文件路径:
    • 在protobuf闭包内添加如下配置,则生成的文件会在响应的目录,如"$projectDir/src/main"会在目录src/main/debug/java/包名/下生成
         generatedFilesBaseDir = "$projectDir/src/main"
    
    • 1
    如果要自定义多个则需要写多个proto文件,编译会生成多个相关文件。
    代码如下:
    syntax = "proto3";
    
    option java_package = "edu.test.demo";
    option java_multiple_files = true;
    
    message DataPreference{
        string info = 1;
        int32 order = 2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    则生成的文件如下图,做了生成文件路径配置

    多个proto编译生成文件

    开始使用

    1. 扩展定义

    const val DATA_STORE_USER_FILE_NAME = "user_prefs.pb"
    val Context.userDataStore : DataStore<UserPreferences> by dataStore(
        fileName = DATA_STORE_USER_FILE_NAME,
        serializer = UserPreferencesSerializer
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 使用

    代码如下:
    
                val user = userDataStore.data.first()
                Log.d(TAG.TAG, "user is ${user.name}")
                Log.d(TAG.TAG, "user is ${user.age}")
                Log.d(TAG.TAG, "user is ${user.sex}")
                Log.d(TAG.TAG, "user is ${user.tall}")
                Log.d(TAG.TAG, "user is ${user.weight}")
    
                //更新
                userDataStore.updateData {
                    it.toBuilder().setName("张三").setAge(16).setSex(1).setWeight(65.0f).setTall(175.0f)
                        .build()
                }
                //读取
                val userUpdate = userDataStore.data.first()
                Log.d(TAG.TAG, "userUpdate is ${userUpdate.name}")
                Log.d(TAG.TAG, "userUpdate is ${userUpdate.age}")
                Log.d(TAG.TAG, "userUpdate is ${user.sex}")
                Log.d(TAG.TAG, "userUpdate is ${user.tall}")
                Log.d(TAG.TAG, "userUpdate is ${userUpdate.weight}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    日志如下:
    2022-08-05 14:14:51.227 4324-4349/edu.test.demo D/Test-TAG: user is 
    2022-08-05 14:14:51.227 4324-4349/edu.test.demo D/Test-TAG: user is 0
    2022-08-05 14:14:51.227 4324-4349/edu.test.demo D/Test-TAG: user is 0
    2022-08-05 14:14:51.227 4324-4349/edu.test.demo D/Test-TAG: user is 0.0
    2022-08-05 14:14:51.227 4324-4349/edu.test.demo D/Test-TAG: user is 0.0
    2022-08-05 14:14:51.258 4324-4350/edu.test.demo D/Test-TAG: userUpdate is 张三
    2022-08-05 14:14:51.258 4324-4350/edu.test.demo D/Test-TAG: userUpdate is 16
    2022-08-05 14:14:51.258 4324-4350/edu.test.demo D/Test-TAG: userUpdate is 0
    2022-08-05 14:14:51.258 4324-4350/edu.test.demo D/Test-TAG: userUpdate is 0.0
    2022-08-05 14:14:51.258 4324-4350/edu.test.demo D/Test-TAG: userUpdate is 65.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    分析:
    • 可以看出在未设置值之前,默认对象是可以读出来的,string的默认值为空,int32为0,float为0.0.
    • 在设置值之后我们读取到的就是设置的最新值。
    补充:
    • 其实我们可以看到生成的datastore文件,目录是data/data/包名/files/datastore/,如下图所示:
      生成的datastore文件

    使用补充,如果要使用多个自定义类型

    • 需要多个proto文件,上面已经做了说明,同时需要多个序列化生成器。
    • 会生成多个相关类,上面已经做了说明。
    • 扩展及使用方式都一样,也会生成多个存储文件,如下图所示:
      使用多个proto自定义类型生成的datastore文件

    总结

    • 本篇主要对Proto DataStore的使用及注意事项做了介绍。
    • 本篇演示了Proto DataStore的简单使用过程。
  • 相关阅读:
    Springboot属性注入
    linux--gdb的使用
    【Java集合类面试十八】、ConcurrentHashMap是怎么分段分组的?
    JavaScript Continue语句
    arpspoof 安装和使用
    344. Reverse String
    【云原生|Docker】Docker镜像操作
    Gradle在Androidstudio中下载超时提示Download info Connect timed out
    【Glide 】框架在内存使用方面的优化
    Algorithm Review 5
  • 原文地址:https://blog.csdn.net/jinjin10086/article/details/126176246