一文了解 kotlin 序列化

在 Kotlin 中,我们可以使用 Serialization 来实现序列化和反序列化。目前支持的格式有如下几种,需要注意除了 JSON 外,其他格式都是实验性质的,api可能会变更。因此下面关于 Serialization 的使用,都是以 JSON 为例。

Serialization 的使用

  • 第一步:在根目录下的 build.gradle 文件中声明插件
groovy 复制代码
plugins { 
    id 'org.jetbrains.kotlin.jvm' version '2.1.0' 
    id 'org.jetbrains.kotlin.plugin.serialization' version '2.1.0' 
}

然后在 app 的 build.gradle 中引入插件

bash 复制代码
plugins {
    id 'org.jetbrains.kotlin.plugin.serialization'
}
  • 第二步:添加Serialization的依赖
groovy 复制代码
dependencies { 
    implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3' 
}
  • 第三步:声明一个需要系列化的类。需要注意,序列化的类必须带上 @Serializable 注解,不然序列化/反序列化时会报错。
kotlin 复制代码
@Serializable
data class UserInfo(
    val name: String,
    val phone: Long,
    val age: Int
)
  • 第四步:系列化和反序列化
kotlin 复制代码
val userInfo = UserInfo("John", 1234567890, 30)
// 序列化
val stringContent = Json.encodeToString(userInfo)
println("stringContent = $stringContent")
// 反序列化
val decodeUserInfo = Json.decodeFromString<UserInfo>(stringContent)
println("userInfo2 = $decodeUserInfo")

效果如下图所示:

默认值

当我们反序列化时的 json 字符串中不包含对象声明的属性字段时,反序列化会失败。代码示例如下,json字符串没有包含 name 字段,这时反序列化会报 JsonDecodingException 异常。

ini 复制代码
val decodeUserInfo = Json.decodeFromString<UserInfo>("""{"phone":1234567890,"age":30}""")
println("decodeUserInfo = $decodeUserInfo")

如果需要解决这个问题,你可以给你的属性添加默认值。代码示例如下:

kotlin 复制代码
// 默认值为 null,反序列化结果为: UserInfo(name=null, phone=1234567890, age=30)
@Serializable
data class UserInfo(
    val name: String? = null,
    val phone: Long,
    val age: Int
)
// 默认值不为 null,反序列化结果为: UserInfo(name=默认用户, phone=1234567890, age=30)
@Serializable
data class UserInfo(
    val name: String = "默认用户",
    val phone: Long,
    val age: Int
)

@Required 和 @Transient

除了 @Serializable 注解外,Serialization 还有 @Required@Transient 需要了解下。其中 @Required 注解用来声明属性,表明该属性在反序列化中必须存在(即使有默认值也不行),否则失败。代码示例如下:

kotlin 复制代码
@Serializable
data class UserInfo(
    val name: String? = null, // 存在默认值
    val phone: Long,
    val age: Int
)

// 没有出现,则反序列化失败
val decodeUserInfo2 = Json.decodeFromString<UserInfo>("""{"phone":1234567890,"age":30}""")
println("decodeUserInfo2 = $decodeUserInfo2")

运行效果如下:

@Transient 则是让这个属性不参加序列化,代码示例如下:

kotlin 复制代码
@Serializable
data class UserInfo(
    val name: String,
    val phone: Long,
    val age: Int,
    @Transient
    var address: String = "" // @Transient 修饰的属性必须有默认值
)

val userInfo = UserInfo(null, 1234567890, 30, address = "Beijing")
val stringContent = Json.encodeToString(userInfo)
println("stringContent = $stringContent")

运行效果如下:

自定义 Serializer

在 kotlin 中除了一般的数据结构外,还有枚举和密封类。有时候我们想要把后台的一些数字类型转换为对应的枚举或者密封类,这时就可以自定义 Serializer。代码示例如下:

kotlin 复制代码
@Serializable(with = UserTypeKSerializer::class)
enum class UserType(val code: Int) {
    Teen(0),
    Adult(1)
}

class UserTypeKSerializer : KSerializer<UserType> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UserType", PrimitiveKind.STRING)

    override fun deserialize(decoder: Decoder): UserType {
        val code = decoder.decodeInt()
        return UserType.values().firstOrNull { it.code == code } ?: UserType.Teen
    }

    override fun serialize(encoder: Encoder, value: UserType) {
        encoder.encodeInt(value.code)
    }

}

其中 UserTypeKSerializer 就是我们自定义的序列化类。内部的 SerialDescriptor 属性是一个用于描述序列化数据结构的接口,一般使用 PrimitiveSerialDescriptor 来定义基本类型的序列化描述。然后分别在 serialize 方法中自定义序列化过程;在 deserialize 方法中定义反序列化过程。

泛型的支持

同时 kotlin 的序列化还支持对泛型进行处理。代码示例如下:

kotlin 复制代码
val userInfo = UserInfo<Int>("John", UserType.Teen, 2)
// 序列化
val stringContent = Json.encodeToString(userInfo)
println("stringContent = $stringContent")
// 反序列化
val decodeUserInfo = Json.decodeFromString<UserInfo<Int>>(stringContent)
println("userInfo = ${decodeUserInfo}")

val userInfo1 = UserInfo<String>("John", UserType.Teen, "str")
// 序列化
val stringContent1 = Json.encodeToString(userInfo1)
println("stringContent = $stringContent1")
// 反序列化
val decodeUserInfo1 = Json.decodeFromString<UserInfo<String>>(stringContent1)
println("userInfo1 = ${decodeUserInfo1}")

效果如下图所示:

参考

相关推荐
alexhilton6 小时前
群星闪耀的大前端开发
android·kotlin·android jetpack
五味香1 天前
Java学习,反射
android·java·开发语言·python·学习·flutter·kotlin
大耳猫3 天前
Android Camera2采集并编码为H.264
android·kotlin·相机·h.264
邓孟鑫4 天前
Android实现桌面小部件:今天吃什么
android·kotlin·小部件
zhangphil7 天前
Android Glide批量加载Bitmap,拼接组装大Bitmap,更新单个AppCompatImageView,Kotlin(2)
android·kotlin·glide
sinat_384241097 天前
带有悬浮窗功能的Android应用
android·windows·visualstudio·kotlin
Biomamba生信基地7 天前
R语言基础| 时间序列分析
开发语言·r语言·kotlin·编程
大耳猫8 天前
Android 基于Camera2 API进行摄像机图像预览
android·kotlin·相机·camera
MYBOYER8 天前
Kotlin DSL Gradle 指南
android·开发语言·kotlin