关键词:
我们之前已经 分享 了 Proto DataStore 和 Preferences DataStore 的使用方法。这两个 DataStore 版本都会在后台使用 Protos 对数据进行序列化。您也可以使用 Kotlin 序列化,结合使用 DataStore 与自定义数据类。这有助于减少样板代码,且无需学习或依赖于 Protobuf 库,同时仍可以为数据提供架构。
您需要完成以下几项操作:
- 定义数据类
- 确保您的数据类不可变
- 使用 Kotlin 序列化实现 DataStore 序列化器
- 开始使用
定义数据类
Kotlin 数据类 非常适合与 DataStore 结合使用,这是因为它们能够与 Kotlin 序列化无缝协作。DataStore 会依赖数据类自动生成的 equals
和 hashCode
。数据类也会生成便于调试和更新数据的 toString
和 copy
函数。
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class UserPreferences(
val showCompleted: Boolean,
val sortOrder: SortOrder
)
确保您的数据类不可变
确保您的数据类不可变是非常重要的,这是因为 DataStore 无法兼容可变类型。结合使用可变类型与 DataStore 会导致难以捕获的错误和竞争条件。数据类并非一定不可变。
Vars 是可变的,所以您应使用 vals 代替:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class MyData(
- var num: Int
+ val num: Int
)
- myObj.num = 5 // Fails to compile when num is val
+ val newObj = myObj.copy(num = 5)
数组是可变的,所以您不应将其公开。
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class MyData(
- var num: IntArray
)
- myObj.num = 5 // This would mutate your object
即使将只读列表用作数据类的一部分,该数据类也仍为可变的。您应考虑改用 不可变/持久化集合:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class MyData(
- val nums: List<Int>
+ val nums: PersistentList<Int>
)
- val myInts = mutableListOf(1, 2, 3, 4)
- val myObj = MyData(myInts)
- myInts.add(5) // Fails to compile with PersistentList, but mutates with List
+ val newData = myObj.copy(
+ nums = myObj.nums.mutate it += 5 // Mutate returns a new PersistentList
+ )
将可变类型用作数据类的一部分会令数据类变为可变状态。您不应采取上述做法,反而要确保所有内容都是不可变类型。
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class MyData(
- val mutableType: MutableType
)
- val myType = MutableType()
- val myObj = MyData(myType)
- myType.mutate()
实现 DataStore 序列化器
Kotlin 序列化支持包括 JSON 和协议缓冲区在内的 多种格式。我将在此处使用 JSON,因为它十分常见、易于使用且会以明文形式进行存储,便于调试。Protobuf 也是一个不错的选择,因为它规模更小、速度更快且兼容 protobuf-lite。
要使用 Kotlin 序列化读取数据类并将其写入 JSON,您需要使用 @Serializable
注释数据类并使用 Json.decodeFromString<YourType>(string)
和 Json.encodeToString(data)
。以下是带有 UserPreferences
的示例:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
@Serializable
data class UserPreferences(
val showCompleted: Boolean = false,
val sortOrder: SortOrder = SortOrder.None
)
object UserPreferencesSerializer : Serializer<UserPreferences>
override val defaultValue = UserPreferences()
override suspend fun readFrom(input: InputStream): UserPreferences
try
return Json.decodeFromString(
UserPreferences.serializer(), input.readBytes().decodeToString())
catch (serialization: SerializationException)
throw CorruptionException("Unable to read UserPrefs", serialization)
override suspend fun writeTo(t: UserPreferences, output: OutputStream)
output.write(Json.encodeToString(UserPreferences.serializer(), t).encodeToByteArray())
⚠️ 将 Parcelables 与 DataStore 一起使用并不安全,因为不同 Android 版本之间的数据格式可能会有所变化。
使用序列化器
在您构建时,将您创建的序列化器传递到 DataStore:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
val Context.dataStore by dataStore("my_file.json", serializer = UserPreferencesSerializer)
其读取数据看起来与使用 protos 进行读取一样:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
suspend fun getShowCompleted(): Boolean
context.dataStore.data.first().showCompleted
您可以使用生成的 .copy() 函数更新数据:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
suspend fun setShowCompleted(newShowCompleted: Boolean)
// This will leave the sortOrder value untouched:
context.dataStore.updateData it.copy(newShowCompleted = showCompleted)
总结
结合使用 DataStore 与 Kotlin 序列化和数据类可减少样板文件并有助于简化代码,但您必须多加小心,避免因为可变性而引发错误。您只需定义数据类和实现序列化器即可。快来动手尝试一下吧!
如要详细了解 DataStore,您可以查看我们的 文档 并获得一些使用 Proto DataStore 和 Preferences DataStore Codelab 的实践经验。
有没有办法在 Kotlin 中使用 JSON 序列化枚举的所有值?
】有没有办法在Kotlin中使用JSON序列化枚举的所有值?【英文标题】:IsthereawaytoserializeallvaluesofanenumwithJSONinKotlin?【发布时间】:2021-06-1806:25:26【问题描述】:我有以下枚举:enumclassDifficultyEASY,MEDIUM,HARD我的RestAPI以以下方式工作:... 查看详情
kotlin用@parcelize实现序列化parcelable(代码片段)
...简介使用总结简介在Android项目中经常要对Bean进行Parcelable序列化,也有很多序列化工具。Android中提倡通过实现Parcelable来对对象序列化,但是如果是使用Java开发实现起来就比较繁琐,而Kotlin提供了@Parcelize,可... 查看详情
androidjetpack组件datastore的使用和简单封装(代码片段)
...项③配置协议缓冲区2.创建proto文件3.配置proto文件4.创建序列化器5.对象写入和取出六、源码前言 也许你是第一次听说这个DataStore,也许你有所耳闻, 查看详情
kotlin函数式编程③(早集合与惰性集合|惰性集合-序列|generatesequence序列创建函数|序列代码示例|take扩展函数分析)(代码片段)
...合中集合元素的初始化是惰性初始化;二、惰性集合-序列Kotlin中提供了一个惰性集合,称为序列Sequence;在序列中,不记录元素个数,也不对其内容进行排序,在该<fontcolor=bluegreen序列中元素可能有无限多个;序列中的元素是由数据... 查看详情
kotlin函数式编程③(早集合与惰性集合|惰性集合-序列|generatesequence序列创建函数|序列代码示例|take扩展函数分析)(代码片段)
...合中集合元素的初始化是惰性初始化;二、惰性集合-序列Kotlin中提供了一个惰性集合,称为序列Sequence;在序列中,不记录元素个数,也不对其内容进行排序,在该<fontcolor=bluegreen序列中元素可能有无限多个;序列中的元素是由数据... 查看详情
androiddatastore使用详解(代码片段)
...tails/127358235本文出自【赵彦军的博客】文章目录概述使用DataStore本地数据查看DataStore文件Key的枚举同步API清除内容包含keySharedPreferences数据迁移DataStore源码概述官方文档:https://developer.android.com/topic/libraries/architecture/datastoreJet... 查看详情
如何在 kotlin 中序列化 lambda
】如何在kotlin中序列化lambda【英文标题】:Howtoserializealambdainkotlin【发布时间】:2019-03-1012:21:23【问题描述】:我正在尝试像在java8中那样序列化一个lambda,其执行方式如下:Runnabler=(Runnable&Serializable)()->doSomething();;但是当它... 查看详情
使用 Retrofit 处理 Kotlin 序列化 MissingFieldException
】使用Retrofit处理Kotlin序列化MissingFieldException【英文标题】:HandlingKotlinSerializationMissingFieldExceptionwithRetrofit【发布时间】:2020-02-0812:21:28【问题描述】:我将kotlinx.serialization与retrofit结合使用。我收到的json响应会根据它包含的属... 查看详情
kotlin一个好用的新功能:parcelize
在开发中,如果有需要用到序列化和反序列化的操作,就会用到Serializable或者Parcelable,它们各有优缺点,会适用于不同的场景。Serializable的优点是实现简单,你只需要实现一个Serializable接口,并不需要任何额外的代码,但是它... 查看详情
kotlin中json的序列化与反序列化--gsonmoshi(代码片段)
文章目录Kotlin中Json的序列化与反序列化--Gson、Moshi实体类集成方式GsonMoshi非空类型序列化反序列化结论可空类型序列化反序列化结论总结Kotlin中Json的序列化与反序列化–Gson、Moshi在App的开发中避免不了需要和Json格式的数据打交... 查看详情
Google Datastore 中的原子序列计数器
】GoogleDatastore中的原子序列计数器【英文标题】:AtomicsequencecountersinGoogleDatastore【发布时间】:2017-11-1312:00:09【问题描述】:我们有一个在GoogleAppEngine中运行的应用程序,作为其操作的一部分,它会生成序列号。这些数字必须满... 查看详情
如何使用 Kotlin 序列化解析 JSON 对象列表中的第一个属性?
】如何使用Kotlin序列化解析JSON对象列表中的第一个属性?【英文标题】:HowtoparsefirstpropertyinlistofJSONobjectsusingKotlinSerialization?【发布时间】:2020-11-0111:17:22【问题描述】:我正在使用Kotlin序列化来解析JSON数据。我只想将第一种类... 查看详情
杰克逊 Kotlin 控制器中请求正文的序列化不与 restTemplate 一起使用,与邮递员一起使用
】杰克逊Kotlin控制器中请求正文的序列化不与restTemplate一起使用,与邮递员一起使用【英文标题】:JacksonSerialisationofRequestBodyinKotlinControllernotworkingwithrestTemplate,workswithpostman【发布时间】:2021-06-0517:29:24【问题描述】:我无法弄... 查看详情
在java中使用kotlin库(代码片段)
...在AndroidStudio中使用GitHub库(MeowBottomNavigation)。但是它用kotlin编写,我不能使用它中的监听器。唯一给出的就是这个bottomNavigation.setOnShowListenerbottomNavigation.setOnClickMenuListener建议显示使用(功能1)我不确定如何在java中实现它。任... 查看详情
在构建版本中找不到数据类 Kotlin 的序列化程序
】在构建版本中找不到数据类Kotlin的序列化程序【英文标题】:SerializerfordataclassKotlinnotfoundatbuildrelease【发布时间】:2021-04-0304:26:13【问题描述】:我想将我的json字符串响应从API转换为对象:valobj=Json.decodeFromString<MyModel>(json... 查看详情
列表的 Kotlin Gson 自定义反序列化器
】列表的KotlinGson自定义反序列化器【英文标题】:KotlinGsoncustomdeserializerforlist【发布时间】:2018-01-0119:57:42【问题描述】:如何在Gson中注册自定义Json反序列化器?当我在Java代码中注册反序列化器时一切正常,但是当我将Kotlin转... 查看详情
kotlin实现parcelable(代码片段)
...e:Int):Parcelable@Parcelize 要求在主要构造函数中声明所有序列化属性。该插件会针对每个属性发出警告,并在类正文中声明一个后备字段。此外,如果主构造函数的某些参数不是属性,就不能应用 @Parcelize。如果... 查看详情
如何使用 Gson @SerializedName 注释在 Kotlin 中反序列化嵌套的 Json API 响应
】如何使用Gson@SerializedName注释在Kotlin中反序列化嵌套的JsonAPI响应【英文标题】:HowtodeserializenestedJsonAPIresponseinKotlinusingGson@SerializedNameannotations【发布时间】:2022-01-1315:10:35【问题描述】:我正在将一个项目迁移到一个新的API,... 查看详情