Moshi
Moshi 是面向 Android、Java 和 Kotlin 的现代 JSON 库,它可以很容易地将 JSON 解析为 Java 和 Kotlin 类。另外,Moshi 是由 Square 公司所开发,且Moshi 的贡献者也是 Gson 的主要贡献者。
传统 Java Json 库(基于反射)用于 Kotlin 主要产生两个问题:
- 不支持空安全。在 Kotlin 中变量一般是默认为非空的,若 Json 为空则解析出
null
并不会抛出异常,直到数据被使用时才会抛出,这是很诡异的,因为定义为非空的变量是不需要判空的,但实际上是为null
。 - 不支持默认参数。Kotlin 的 data class 和默认参数的语法极大地方便了开发,但是在使用传统 Json 解析库时往往会遇到两个问题:
- 默认参数失效
- 解析失败(因为没有无参构造方法)
若使用 Moshi,则不会出现这些问题。
因此,如果项目使用 Kotlin 进行开发,Moshi 无疑是最好的选择。
基础使用
Dependency
implementation("com.squareup.moshi:moshi-kotlin:1.13.0")
kapt("com.squareup.moshi:moshi-kotlin-codegen:1.13.0")
在 Kotlin 中使用 Moshi 有两个方案:
- 使用 Kotlin 反射
- 使用注解生成
因为 Kotlin 的反射库将近 2MB,所以一般采用注解生成,而且理论上会比反射效率更高,因为大多数工作在编译器进行编译时就完成了。
Moshi 使用 Adapter
类负责序列化和反序列化,每个 Kotlin 类对应一个 Adapter,命名规则为 数据类名 + JsonAdapter
,借助内置的基本数据类型从而实现任意类的解析(即使不是基本数据类型,也可以进行转换),这里可以利用注解来实现。
PS:传统的 Json 库中,每当读取到一个 Json 属性可以利用反射找到 Class
中对应的属性字段进行赋值。现在我们不再使用反射,那么怎么找到是哪个变量呢?那就是在编译时把已知变量全部列出来,没有列出来的变量就忽略,负责这个工作的就是
Adapter。
只需要在需要序列化(反序列化)的类上加上 @JsonClass(generateAdapter = true)
注解就行了。
@JsonClass(generateAdapter)
data class Person(
val name: String,
val age: Int,
val sex: Boolean
)
之后的使用与 Gson 类似。
Bean
val json = "..."
val moshi: Moshi = Moshi.Builder().build()
val jsonAdapter = moshi.adapter(Person::class.java)
val person: Person = jsonAdapter.fromJson(json)
实际使用中可以将 Moshi 作为单例,也可通过 Hilt 提供,此处不展开。
Moshi 异常处理也非常规范,一共只会抛出两种异常:
IOException
:读取 Json 过程中出现 IO 异常,或 Json 格式错误。JsonDataException
:数据类型不匹配。
List
如果是要解析成集合,需要先用 Types.newParameterizedType()
包装一下:
val personArrayJson = "..."
val type: Type = Types.newParameterizedType(List::class