当你还在用 Gson 时,Square那帮人已经开发出了 Moshi 了!!
原文地址:好久不见,曾经我们相处得很好,但是是时候说再见了。在你的朋友圈中也许会听到这样的语句(也可能没有),但这并非是本篇文章的主题,我们要谈论的是一个新的关于 Android 和 kotlin 序列化框架!我们需要将 Gson 迁移到 Moshi上面了。当我们谈论为啥Moshi是更优秀的框架,或者怎么迁移到 Moshi之前,我们先来了解一下今天的 Gson 的发展。Gson,what?当我们查
原文地址:
好久不见,曾经我们相处得很好,但是是时候说再见了。
在你的朋友圈中也许会听到这样的语句(也可能没有),但这并非是本篇文章的主题,我们要谈论的是一个新的关于 Android 和 kotlin 序列化框架!我们需要将 Gson 迁移到 Moshi上面了。
当我们谈论为啥Moshi是更优秀的框架,或者怎么迁移到 Moshi之前,我们先来了解一下今天的 Gson 的发展。
Gson,what?
当我们查看 Gson 的github仓库时,它是这么描述的:
一个Java 的序列化/反序列化框架,用来将Java对象转换成Json对象,或者反之。
那么它有以下缺点:
- 很显然它对kotlin并不友好,当然也不是kotlin写的( Gson 是纯Java实现的),所以每个人都可以清楚的意识到 Gson 已经不再是一个现代的开发框架了。它发布于2008年,距离今天已经12年了,看上去已经不更新了(这个的确,看了一下最新的一次更新时间是9个月钱了),完完全全是一个将死的项目了。
- 最近没有更新,上一次更新看上去并没有大的更新或者问题修复(意思就是小修小补),事实上不去碰那些运行得很好的程序,破坏数百万使用Gson库的app 是有道理的(个人认为这里还是正面夸赞了Gson的流行和稳定),但是对于Gson这个项目来说,它似乎正在死去。
- Gson 库的方法数大概为1036个,大概是 Moshi 库中方法数的两倍(Moshi中方法数大概为500)。
- 库的体积 使用 Gson 大约使你的app增大了300kb,而Moshi大概有120kb。
- Gson 使用了 Java的反射实现了序列化和反序列,而 Moshi 使用了 Kotlin 代码自动支持。
- Gson不支持对象属性有默认值。如果在Gson字符串中缺少了属性对应的字符串,即使你设置了默认值,它将来还是null值(这个不是特别明白啥意思)。
假设我们认为 Gson 将死,那我们将走向何方?当然我们可以继续使用 Gson,因为它一直都正常工作!但是对于那些好奇心很强的开发者和kotlin爱好者来说,我们还有 Moshi。接下来我们来看看 什么是 Moshi 和 为什么是 Moshi了。
什么是 Moshi ?
一个 现代的 kotlin 和 Java Json解析库
Moshi的 github地址 (也是大名鼎鼎的square公司出品的)。主要特点是 现代的、kotlin友好的、更快的、拥有大量可靠的功能。先来看看这些牛叉的功能吧:
更好的 API
Moshi提供了更好更现代的 API,你可以使用此强大功能的 API 进行简单整洁的操作。
在 Moshi中 注解(Annotation) 被视为最重要的部分,注解可以允许你添加一些信息来更加细粒度的实现上下文序列化。
- 你可以自定义注解来解析你的Json数据属性,(就像解析颜色使用@ColorInt, @FromHexColor一样)
- 自定义适配器或者上下文反序列可以使功能更加整洁,从而减少样板代码。
- Moshi 拥有更好的、更具人性化的获取序列化失败信息的能力。在当你的app发布之后,从奇怪的堆栈信息中不知道应该做什么,那么Moshi将会是一个巨大的进步(可以帮助你获取异常信息)。
- Moshi 拥有 newBuilder() 方法从上游的Adapter中来帮助创建新的Adapter,这就有点像OkHttp 或者 Okio builder模式了,它超级有用,因为你可以创建独立的Adapter,这样就不需要拥有解析全部对象的Adapter(这句话的意思,需要理解Moshi解析字符流的方式和Gson不一致,Gson是从前到后,一个字符不落下去解析,而Moshi可以直接跳过目标字符,只需要得到自己想要的字符)
- Moshi 支持多态数据类型,同时也支持未知的数据类型的回退。
- Moshi在 Kotlin 中拥有代码自动生成功能,这个很好!在注解的帮助下,你可以更加快速的序列化\反序列化.这个比Gson使用反射方法快多了。
Moshi 的表现
Moshi 比 Gson 要快(通过实验得出结论 [链接]), 而且Moshi消耗的内存更少,这是因为它使用了 Okio,Okio可以在解析Json字符流的过程提前预测或者期望忽略掉未知的、不需要的字段(从而达到速度快、内存小的目的,这里有篇文章讲得很清楚 ). Retrofit底层也是用了 Okio,所以你才会发生什么? Json序列化库(Moshi) 和 网络请求工具(Retrofit) 可以共用它们的缓冲区,这样将会在网络请求和序列化时降低内存的消耗。
理论说的差不多了,看看代码咋写吧
来看看咋样一步一步从Gson迁移到 Moshi 吧。
1. 添加 build.gradle 依赖
/*Moshi*/
def moshiVersion = "1.10.0"
implementation("com.squareup.moshi:moshi:$moshiVersion")
kapt("com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion")
implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
2. 将所有的 @SerializedName 替换成 @Json
data class MediaCandidateData(
@SerializedName("width")
val width: Int,
@SerializedName("height")
val height: Int,
@SerializedName("url")
val url: String
)
替换为:
data class MediaCandidateData(
@Json(name = "width")
val width: Int,
@Json(name = "height")
val height: Int,
@Json(name = "url")
val url: String
)
3. 给所有的Data Class 添加 @JsonClass(generateAdapter = true) 注解
给所有的Data Class 添加 @JsonClass(generateAdapter = true)注解,将会参与到序列化\反序列化的进程中。它帮助Moshi使用代码自动生成而非使用将会降低速度的反射。
@JsonClass(generateAdapter = true)
data class MediaCandidateData(
@Json(name = "width")
val width: Int,
@Json(name = "height")
val height: Int,
@Json(name = "url")
val url: String
)
4. 替换Gson的实例为 Moshi
如果使用 Dagger 来提供依赖,你可以需要这么干:
@Singleton
@Provides
fun provideGson() = GsonBuilder().setLenient().create()
替换为:
@Singleton
@Provides
fun providesMoshi() = Moshi.Builder().build()
5. 使用 Retrofit时替换 converter
当你使用Retrofit 和 Dagger 时,你可能需要这么做:
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient, gson: Gson) = Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(BASE_ENDPOINT)
.build()
现在替换为:
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient, mosh: Moshi) = Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(MoshiConverterFactory.create(mosh))
.baseUrl(BASE_ENDPOINT)
.build()
就是这么简单,从Gson迁移到 Moshi非常简单。
当然也有些特例需要单独讲明,这可能需要下篇文章说明了。
更多推荐


所有评论(0)