在kotlin序列化中使用datastore(代码片段)

谷歌开发者 谷歌开发者     2023-02-03     648

关键词:

我们之前已经 分享Proto DataStore 和 Preferences DataStore 的使用方法。这两个 DataStore 版本都会在后台使用 Protos 对数据进行序列化。您也可以使用 Kotlin 序列化,结合使用 DataStore 与自定义数据类。这有助于减少样板代码,且无需学习或依赖于 Protobuf 库,同时仍可以为数据提供架构。

您需要完成以下几项操作:

  • 定义数据类
  • 确保您的数据类不可变
  • 使用 Kotlin 序列化实现 DataStore 序列化器
  • 开始使用

定义数据类

Kotlin 数据类 非常适合与 DataStore 结合使用,这是因为它们能够与 Kotlin 序列化无缝协作。DataStore 会依赖数据类自动生成的 equalshashCode。数据类也会生成便于调试和更新数据的 toStringcopy 函数。

/* 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 DataStorePreferences 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,... 查看详情