Android笔记(二十):JetPack DataStore 之 Proto DataStore

Jetpack DataStore 是一种数据存储解决方案,主要适用于小型数据的处理。它可以通过协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致的事务方式存储数据。DataStore有两种实现方式(1)Preferences DataStore 和 (2)Proto DataStore。Proto DataStore将数据作为自定义类型的实例进行存储。

一.了解Protocol Buffers

在了解Protocol Buffers之前需要了解序列化和反序列化。

序列化:就是将代码中生成的对象生成二进制流形式保存起来,也可以将二进制流写入到文件或其他媒介中存储或传输(如网络传输)。
反序列化:就是将二进制流转换成代码可以处理的对象。

Protocol Buffers翻译成协议缓存区,是Google公司推出的一种语言中立、平台中立的数据序列化的方法,类似xml,但是比xml更小、更加灵活,处理更快。
在这里插入图片描述

Protobuffer的工作流程:
首先需要通过在 .proto 文件中定义消息类型来指定数据的结构以及要序列化的服务;
接着根据proto文件可以在不同语言的代码中,将该文件自动生成对应的结构类型(消息的逻辑结构);根据结构类型创建对应的消息(要处理对象)。
然后,编译器使用协议对其进行编译。按照预先定义的架构用于对序列化数据进行编码和解码。解码生成序列化数据,以二进制数据的形式保存起来;也可以对可序列化数据进行编码,在代码中将这些二进制数据转换成代码需要的对象。

二.使用Proto DataStore

Proto Datastore采用Protocol Buffers来定义架构,使得按键存取值可以使用正确的数据类型。Proto DataStore 实现使用 DataStore 和协议缓冲区将类型化对象保留在磁盘上。仍然使用Android笔记(十九)类似的实例,通过示例来了解Proto DataStore的应用。

1.项目模块的build.gradle.kt修改配置

因为构建配置语言采用Kotlin DSL,因此配置的相同选项与谷歌官方网站介绍的Groovy DSL配置有细节不同。

添加协议缓存区插件

plugins{

id(“com.google.protobuf”) version “0.9.4”
}

添加协议缓存区和Proto DataStore依赖项

implementation(“androidx.datastore:datastore-core:1.0.0”)
implementation(“com.google.protobuf:protobuf-javalite:3.19.4”)

配置协议缓存区
在build.gradle.kt中增加如下protebuf的配置

protobuf {protoc {artifact = "com.google.protobuf:protoc:3.23.4"}// 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().forEach {task->task.builtins {id("java"){option("lite")}}}}}

另外,还需要指定转换文件的源目录,需要在build.gradle.kt中设置如下配置:

android{
...sourceSets.named("main"){proto{srcDir("src/main/proto")}}
}

2. 创建.proto文件

(1)安装Protocol Buffers插件
为了在Android Studio中更容易编辑.proto文件,可以在Android Studio中安装Protocol Buffers插件,如下图所示:
在这里插入图片描述
(2)创建.proto文件
在.proto文件中定义架构,采用上例的两个属性:账号名name和访问次数counter。
在app/src下创建一个新的目录,命名为proto,然后在新创建的proto目录下定义如下UserPreferences.proto文件:
在这里插入图片描述

UserPerferences.proto文件内容如下:

syntax = "proto3";
//java_package选项:java生成的类所在的包
option java_package = "com.eyes.datastore.utils";
//java_multiple_files选项:如果为 false,则只会.java为此文件生成一个.proto文件,如果true,.java将为每个 Java 类/枚举/等生成单独的文件。
option java_multiple_files = true;message UserPreferences{int32 counter = 1;//第一个关键字对应的取值类型为int32string email = 2; //第二个关键字对应的取值类型是stringoptional string name = 3; //可选项,第三个关键字对应的取值类型是string
}

有一个细节需要注意,.proto文件只能在project层次结构下可以查看到该文件。如果采用Android层次结构,则无法在目录层次结构中找到.proto文件。
在这里插入图片描述
(3)构建模块,自动生成对应Java代码
然后,构建该项目模块,可以发现在模块的project项目层次下的模块名-》build-》generated-》source-》proto-》java-》指定包名下会自动生成对应的java代码,如下图所示:
在这里插入图片描述

3.创建序列化器

数据序列化分为两个步骤:

定义一个实现 Serializer 的类,其中 T 是 proto 文件中指定的类型。此序列化器类会告知 DataStore 如何读取和写入数据类型。
创建 DataStore 实例,其中 T 是在 proto 文件中定义的类型。在 Kotlin文件顶层调用该实例一次,便可在应用的所有其余部分通过此属性委托访问该实例。

object UserPreferencesSerializer: Serializer<UserPreferences> {override val defaultValue: UserPreferencesget() = UserPreferences.getDefaultInstance()override suspend fun readFrom(input: InputStream): UserPreferences {try {return UserPreferences.parseFrom(input)} catch (e: InvalidProtocolBufferException) {throw CorruptionException("无法读取UserPreferences.proto")}}override suspend fun writeTo(t: UserPreferences, output: OutputStream) = t.writeTo(output)
}

在文件的顶层创建Proto DataStore对象,代码如下:

val Context.userPreferencesDataStore: DataStore<UserPreferences> by dataStore(fileName = "UserPreferences.pb",serializer = UserPreferencesSerializer
)

上述的代码中:

filename 参数会告知 DataStore 使用哪个文件存储数据
serializer 参数会告知 DataStore 在第 1 步中定义的序列化器类的名称。

4. 实体类UserBean

为了在Kotlin代码中更好地处理数据,这里定义一个实体类UserBean,使得可以将序列化的数据生成对应的UserBean对象。

data class UserBean(val counter:Int,val email:String,var name:String="客人")

这个实体类是可选项,可以根据项目的需求不需要定义。

5. 实用类DataStoreUtils

定义DataStoreUtils实体类,实现对数据的具体的读写操作,代码如下:

class DataStoreUtils(val context: Context) {val userFlow: Flow<UserBean> =context.userPreferencesDataStore.data.map{userPreferences->UserBean(userPreferences.counter,userPreferences.email,userPreferences.name)}suspend fun updateData(email:String,name:String="无昵称"){context.userPreferencesDataStore.updateData {userPreferences->userPreferences.toBuilder().setCounter(userPreferences.counter+1).setEmail(email).setName(name).build()}}
}

6. 定义界面MainScreen

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(dataStoreUtils: DataStoreUtils, modifier:Modifier = Modifier){val context = LocalContext.currentvar emailInput by remember{ mutableStateOf("guest@eyes.com") }var nameInput by remember{ mutableStateOf("客人") }var rememberInput by remember{ mutableStateOf(false) }var content by remember{ mutableStateOf("") }val scope = rememberCoroutineScope()//读取数据LaunchedEffect(Unit){dataStoreUtils.userFlow.collect{userBean->content = "账号:${userBean.email},昵称:${userBean.name}访问次数是:${userBean.counter}"}}Column{TextField(modifier = Modifier.fillMaxWidth(),value = emailInput,onValueChange = {it:String->emailInput = it},label ={Text("输入账号")},leadingIcon = {Icon(imageVector = Icons.Filled.Email,contentDescription = "账号")})TextField(modifier = Modifier.fillMaxWidth(),value = nameInput,onValueChange = {it:String->nameInput = it},label ={Text("输入昵称")},leadingIcon = {Icon(imageVector = Icons.Filled.Person,contentDescription = "昵称")})Row{Checkbox(checked = rememberInput, onCheckedChange ={rememberInput = itif(rememberInput)scope.launch {//写入数据dataStoreUtils.updateData(emailInput,nameInput)}})Text("记住账号")}if(!emailInput.isBlank())Text(text = content ,fontSize=20.sp)}
}

7. 定义主活动MainActivity调用主界面MainScreen

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ForCourseTheme {Surface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colorScheme.background) {MainScreen(DataStoreUtils(this))}}}}
}

运行结果如下图所示

在这里插入图片描述
通过Device Explorer查看对应的项目模块的文件处理情况,在data->data->模块包名->files->datastore目录下的文件可序列化的数据存储在UserPerferences.pb中,具体文件内容如下图所示:
在这里插入图片描述

参考文献

DataStore
https://developer.android.google.cn/topic/libraries/architecture/datastore?hl=zh-cn

Gradle Kotlin DSL Primer
https://docs.gradle.org/current/userguide/kotlin_dsl.html

customizing-protobuf-compilation
https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/292426.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“智”绘出海新航道,亚马逊云科技携手涂鸦智能助力智能家居企业全球化

随着人工智能、5G等技术的快速发展&#xff0c;智能家居行业呈现高速发展的态势。Statista数据显示&#xff0c;2022年全球智能家居行业支出总值为1145亿美元&#xff0c;欧美地区以较早的智能家居普及率&#xff0c;率先进入全屋智能时代&#xff0c;其中欧盟区国家家用智能设…

simulink代码生成(一)——环境搭建

一、安装C2000的嵌入式环境&#xff1b; 点击matlab附加功能&#xff0c; 然后搜索C2000&#xff0c;安装嵌入式硬件支持包&#xff1b;点击安装即可&#xff1b;&#xff08;目前还不知道破解版的怎么操作&#xff0c;目前我用的是正版的这样&#xff0c;完全破解的可能操作…

flink watermark 实例分析

WATERMARK 定义了表的事件时间属性&#xff0c;其形式为: WATERMARK FOR rowtime_column_name AS watermark_strategy_expression rowtime_column_name 把一个现有的列定义为一个为表标记事件时间的属性。该列的类型必须为 TIMESTAMP(3)/TIMESTAMP_LTZ(3)&#xff0c;且是 sche…

Sharding JDBC 学习了解 - 总览和概念

第一部分&#xff1a;概述 ShardingSphere是一个由一套分布式数据库中间件解决方案组成的开源生态圈&#xff0c;包括Sharding-JDBC、Sharding-Proxy和Sharding-Proxy 3个独立产品。它们都提供了数据分片、分布式事务、数据库编排等功能&#xff0c;适用于Java同构、异构语言、…

docker学习(十一、Redis集群存储数据方式)

文章目录 一、集群数据存储1.单机连接集群问题2.集群方式连接redis存储数据 二、 查看集群信息 docker搭建Redis集群相关知识&#xff1a; docker学习&#xff08;九、分布式存储亿级数据知识&#xff09; docker学习&#xff08;十、搭建redis集群&#xff0c;三主三从&#x…

UE5 Landscape 制作GIS卫星图地形

1. 总体想法&#xff1a; 制作GIS地形&#xff0c;使用Landscaping MapBox是一个好方法&#xff0c;但是区域过大&#xff0c;会占用很多内存 https://blog.csdn.net/qq_17523181/article/details/135029614 如果采用QGis&#xff0c;导出卫星图&#xff0c;在UE5里拼合出地形…

docker 部署kafka

随笔记录 目录 1. 安装zookeeper 2. 安装Kafka 2.1 拉取kafka image 2.2 查询本地docker images 2.3 查看本地 容器&#xff08;docker container&#xff09; 2.3.1 查看本地已启动的 docker container 2.3.2 查看所有容器的列表&#xff0c;包括已停止的容器。 2.4 …

基于ssm二手车交易平台的设计论文

摘 要 进入21世纪网络和计算机得到了飞速发展&#xff0c;并和生活进行了紧密的结合。目前&#xff0c;网络的运行速度以达到了千兆&#xff0c;覆盖范围更是深入到生活中的角角落落。这就促使二手交易网站的发展。二手交易网站可以实现远程购物&#xff0c;远程选择喜欢的商品…

【数学建模美赛F奖速成系列】论文写作技巧+优秀论文讲评

目录 写在前面推荐课程历年优秀美赛论文 写在前面 由于美赛参赛规则是要求提交英文摘要和论文&#xff0c;作为评奖的唯一依据&#xff0c;这就要求参赛学生既要具有较好的数学建模能力&#xff0c;同时也需要具备较高的英语写作水平&#xff0c;并熟练掌握英语论文的写作技巧…

考研数学二内容总结

目录 高等数学 一、函数、极限、连续 考试内容 &#x1f3c1;总结&#xff1a; 考试要求 &#x1f3c1;1&#xff0e;理解函数的概念&#xff0c;掌握函数的表示法&#xff0c;会建立应用问题的函数关系&#xff0e; 2&#xff0e;了解函数的有界性、单调性、周期性和奇…

程序员自由创业周记#20:需求从何而来

程序员自由创业周记#20&#xff1a;需求从何而来 之前看过我周记的朋友应该了解我从7月份开始独立创业以来&#xff0c;主要做了两个产品&#xff0c;一个是加一&#xff0c;一个是Island Widgets - 灵动岛锁屏小组件 &#xff0c;上班的时候工作内容是上级主管分配&#xff0c…

C++基础语法总结

C使用 C的源文件扩展名是&#xff1a;cppC程序的入口是main函数C完全兼容c语言的语法 1、cin、cout C中常使用cin、cout进行控制台的输入和输出 #include <iostream> using namespace std;int main() {cout << "hello world !!!" << endl;retu…