Kotlinx.serialization 使用指南
引言:为什么需要新的序列化方案?
在 Android / Kotlin 项目中,我们习惯于用 Gson/Moshi 来处理 JSON,但随着业务扩大,我们遇到:
| 问题 | 表现 |
|---|---|
| ❌ 反射慢、包体大 | 冷启动有明显反射开销,尤其 fragment/activity 初始化 |
| ❌ 字段兼容差 | 后端新增字段 → JsonSyntaxException |
| ❌ 多态类难处理 | sealed class 支持不友好 |
| ❌ 配置分散 | 需要在 Model 或 Adapter 注册序列化逻辑 |
Kotlinx.serialization 的出现就是为了解决这些痛点。
Kotlinx.serialization 是什么?
一句话定义:
Kotlin 官方提供的 编译期序列化框架,支持 JSON、ProtoBuf、CBOR,跨 JVM / Android / KMM。
特性总结:
✅ 无反射,编译期生成序列化器
✅ Kotlin-first,支持 data/sealed class
✅ 支持多格式 JSON / Protobuf / CBOR
✅ 可与 Ktor / Retrofit 无缝集成
✅ 更轻量小包体,不需要 keep 反射 class
基本用法(3 行代码)
@Serializable
data class User(val id: Long, val name: String)val json = Json { ignoreUnknownKeys = true }val str = json.encodeToString(User(1, "Ling"))
val u = json.decodeFromString<User>(str)
重点:必须加 @Serializable,编译期自动生成序列化器,不用反射。
JSON 配置建议(够用就这个)
val JSONx = Json {ignoreUnknownKeys = true // 多字段容错encodeDefaults = false // 不把默认值写入JSONexplicitNulls = false // 不输出 null 字段isLenient = true // 宽松解析coerceInputValues = true // 类型不匹配挽救
}
开启
ignoreUnknownKeys=true后,后端新增字段不会炸。
常用注解(70% 的问题靠这些解决)
| 注解 | 功能 |
|---|---|
@SerialName("xxx") | JSON key 映射 |
@JsonNames("a","b") | 后端字段不统一时兼容多个 |
@Transient | 不序列化某字段 |
@Contextual | 第三方类,如 UUID、Date |
@Serializable(with=...) | 自定义序列化器 |
多态对象(sealed class 最爽)
@Serializable
sealed class Message {@Serializable @SerialName("text")data class Text(val content: String): Message()@Serializable @SerialName("image")data class Image(val url: String): Message()
}val json = Json { classDiscriminator = "type" }
输出 JSON:
{"type":"text","content":"hello"}
sealed +
classDiscriminator= 强无敌。
tips:
Kotlinx.serialization 对多态对象(sealed class )支持更好用
自定义序列化器(处理后端不稳定 JSON)
例子:后端返回 "timestamp": "1738918293128"(字符串)
object EpochMilliAsString : KSerializer<Long> {override val descriptor = PrimitiveSerialDescriptor("Epoch", PrimitiveKind.STRING)override fun serialize(encoder: Encoder, value: Long) =encoder.encodeString(value.toString())override fun deserialize(decoder: Decoder) =decoder.decodeString().toLong()
}
Retrofit/Ktor 集成(推荐)
Retrofit
val json = Json {ignoreUnknownKeys = true// 过渡期若按内容判别:无需 classDiscriminator// 将来有 type:classDiscriminator = "type"
}val retrofit = Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(json.asConverterFactory("application/json".toMediaType())).build()interface Api {@GET("messages")suspend fun list(): List<Message>
}
Ktor Client
val client = HttpClient(OkHttp) {install(ContentNegotiation) { json(Json {ignoreUnknownKeys = true// classDiscriminator = "type"}) }
}
与 Gson 对比总结
| 对比项 | Gson/Moshi | Kotlinx.serialization |
|---|---|---|
| 性能 | ❌ 反射 | ✅ 编译期生成,无反射 |
| sealed class 多态支持 | ❌ 复杂 | ✅ 一行搞定 |
| Kotlin default 值序列化 | ❌ 不支持 | ✅ 原生支持 |
| 包体积 | ❌ 大 | ✅ 小 |
| 跨平台(KMM) | ❌ 不支持 | ✅ KMM 友好 |
项目落地策略(迁移方案)
建议逐模块迁移:
新模块 → Kotlinx.serialization
旧模块 → 可混用 Gson,不强制一次性改完
迁移 checklist:
-
Model 加
@Serializable -
Json 全局单例(避免频繁创建)
-
Retrofit/Ktor 换 converter
-
sealed class 都替换到多态序列化
下一篇:
Kotlinx.serialization 项目集成
