OkHttp 与 JSON 解析库完美结合:Moshi/Jackson/Gson 实战指南

前言

在现代 Android 开发中,网络请求与 JSON 数据处理是密不可分的。OkHttp 作为强大的 HTTP 客户端,与 JSON 解析库(Moshi/Jackson/Gson)的结合使用,可以极大简化网络请求与数据解析的流程。本文将详细介绍如何将 OkHttp 与这三种主流 JSON 库结合使用,帮助开发者选择最适合自己项目的技术方案。

一、三种 JSON 库概览

1. Gson

  • 优点:Google 官方支持,API 简单易用,社区资源丰富

  • 缺点:性能相对较低,缺乏对 Kotlin 的深度支持

2. Jackson

  • 优点:性能优异,功能全面,支持多种数据格式

  • 缺点:API 较复杂,初始配置繁琐

3. Moshi

  • 优点:专为 Kotlin 设计,轻量高效,与 OkHttp 同属 Square 产品线

  • 缺点:社区相对较小,功能不如 Jackson 全面

二、基础集成与配置

1. 添加依赖

Gradle 配置

// OkHttp 核心库
implementation 'com.squareup.okhttp3:okhttp:4.10.0'// 各 JSON 库选择其一即可
implementation 'com.squareup.moshi:moshi:1.14.0'        // Moshi
implementation 'com.squareup.moshi:moshi-kotlin:1.14.0' // Moshi Kotlin 支持
kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.14.0'  // Moshi 代码生成implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.1' // Jacksonimplementation 'com.google.code.gson:gson:2.10' // Gson

三、OkHttp 与 Moshi 结合使用

1. 基本配置

// 创建 Moshi 实例
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()) // 支持 Kotlin 类.build()// 创建 OkHttpClient
val okHttpClient = OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).build()// 使用示例
suspend fun fetchUser(): User {val request = Request.Builder().url("https://api.example.com/user/1").build()okHttpClient.newCall(request).execute().use { response ->if (!response.isSuccessful) throw IOException("Unexpected code $response")val moshiAdapter = moshi.adapter(User::class.java)return moshiAdapter.fromJson(response.body?.source())!!}
}

2. 配合 Retrofit 使用

val retrofit = Retrofit.Builder().baseUrl("https://api.example.com/").client(okHttpClient).addConverterFactory(MoshiConverterFactory.create(moshi)).build()interface ApiService {@GET("user/{id}")suspend fun getUser(@Path("id") userId: String): User
}

3. 自定义适配器(处理特殊格式)

class DateAdapter {@ToJsonfun toJson(date: Date): String {return SimpleDateFormat("yyyy-MM-dd").format(date)}@FromJsonfun fromJson(dateString: String): Date {return SimpleDateFormat("yyyy-MM-dd").parse(dateString)!!}
}// 使用自定义适配器
val moshi = Moshi.Builder().add(DateAdapter()).add(KotlinJsonAdapterFactory()).build()

四、OkHttp 与 Jackson 结合使用

1. 基本配置

// 创建 ObjectMapper
val objectMapper = ObjectMapper().registerModule(KotlinModule())// 使用示例
fun fetchUser(): User {val request = Request.Builder().url("https://api.example.com/user/1").build()okHttpClient.newCall(request).execute().use { response ->if (!response.isSuccessful) throw IOException("Unexpected code $response")return objectMapper.readValue(response.body?.string(), User::class.java)}
}

2. 配合 Retrofit 使用

val retrofit = Retrofit.Builder().baseUrl("https://api.example.com/").client(okHttpClient).addConverterFactory(JacksonConverterFactory.create(objectMapper)).build()

3. 处理复杂情况

// 配置 ObjectMapper 处理多种情况
val objectMapper = ObjectMapper().apply {registerModule(KotlinModule.Builder().build())configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
}

五、OkHttp 与 Gson 结合使用

1. 基本配置

// 创建 Gson 实例
val gson = GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create()// 使用示例
fun fetchUser(): User {val request = Request.Builder().url("https://api.example.com/user/1").build()okHttpClient.newCall(request).execute().use { response ->if (!response.isSuccessful) throw IOException("Unexpected code $response")return gson.fromJson(response.body?.charStream(), User::class.java)}
}

2. 配合 Retrofit 使用

val retrofit = Retrofit.Builder().baseUrl("https://api.example.com/").client(okHttpClient).addConverterFactory(GsonConverterFactory.create(gson)).build()

3. 自定义类型适配器

val gson = GsonBuilder().registerTypeAdapter(Date::class.java, object : JsonDeserializer<Date> {override fun deserialize(json: JsonElement,typeOfT: Type,context: JsonDeserializationContext): Date {return SimpleDateFormat("yyyy-MM-dd").parse(json.asString)!!}}).create()

六、三种方案对比与选型建议

1. 性能对比

  • Jackson:解析速度最快,内存占用最低

  • Moshi:性能接近 Jackson,略优于 Gson

  • Gson:性能相对较低,但在大多数场景足够

2. 功能对比

特性MoshiJacksonGson
Kotlin 支持✓✓
代码生成
灵活性✓✓✓✓✓✓✓
学习曲线

3. 选型建议

  • 新项目(Kotlin):优先选择 Moshi,特别是与 OkHttp/Retrofit 配套使用

  • 大型复杂项目:考虑 Jackson,特别是需要处理复杂 JSON 结构时

  • 维护旧项目:继续使用 Gson,特别是项目已经大量依赖 Gson 时

七、高级技巧与最佳实践

1. 统一错误处理

inline fun <reified T> OkHttpClient.parseResponse(request: Request): T {this.newCall(request).execute().use { response ->val body = response.body?.string() ?: throw IOException("Empty response")if (!response.isSuccessful) {// 尝试解析错误信息val errorResponse = moshi.adapter(ErrorResponse::class.java).fromJson(body)throw ApiException(code = response.code,message = errorResponse?.message ?: "Unknown error")}return moshi.adapter(T::class.java).fromJson(body)!!}
}

2. 缓存网络响应

inline fun <reified T> OkHttpClient.parseResponse(request: Request): T {this.newCall(request).execute().use { response ->val body = response.body?.string() ?: throw IOException("Empty response")if (!response.isSuccessful) {// 尝试解析错误信息val errorResponse = moshi.adapter(ErrorResponse::class.java).fromJson(body)throw ApiException(code = response.code,message = errorResponse?.message ?: "Unknown error")}return moshi.adapter(T::class.java).fromJson(body)!!}
}

3. 日志拦截器

class JsonPrettyPrintInterceptor : Interceptor {override fun intercept(chain: Interceptor.Chain): Response {val request = chain.request()val response = chain.proceed(request)val content = response.body?.string() ?: return responsetry {val prettyJson = when {content.startsWith("{") -> JsonParser.parseString(content).toString()content.startsWith("[") -> JsonParser.parseString(content).toString()else -> content}Log.d("Network", prettyJson)} catch (e: Exception) {Log.d("Network", content)}return response.newBuilder().body(content.toResponseBody(response.body?.contentType())).build()}
}

八、常见问题解决方案

1. 处理 JSON 字段与 Kotlin 属性名不一致

Moshi:

@Json(name = "user_name") 
val userName: String

Jackson:

@JsonProperty("user_name")
val userName: String

Gson:

@SerializedName("user_name")
val userName: String

2. 处理 null 值

Moshi:

val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).add(NullToEmptyStringAdapter()).build()class NullToEmptyStringAdapter {@FromJson fun fromJson(reader: JsonReader): String {return if (reader.peek() == JsonReader.Token.NULL) {reader.nextNull()""} else {reader.nextString()}}
}

3. 处理多态类型

Jackson:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = "type"
)
@JsonSubTypes(JsonSubTypes.Type(value = Dog::class, name = "dog"),JsonSubTypes.Type(value = Cat::class, name = "cat")
)
abstract class Animal

九、总结

OkHttp 与 JSON 解析库的结合为 Android 开发提供了强大的网络数据处理能力。通过本文的介绍,我们可以看到:

  1. Moshi 是与 Kotlin 最契合的选择,特别适合新项目开发

  2. Jackson 在性能和处理复杂场景方面表现优异

  3. Gson 仍然是不错的选择,特别是对已有项目的维护

无论选择哪种方案,都应考虑项目的具体需求、团队熟悉度和长期维护成本。正确配置和使用这些工具可以显著提高开发效率和应用程序性能。

在实际开发中,建议:

  • 新项目优先考虑 Moshi

  • 性能敏感型项目考虑 Jackson

  • 保持项目的一致性,避免混用多种 JSON 库

  • 合理利用各种高级特性处理复杂场景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90303.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90303.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

An error occurred at line: 1 in the generated java file问题处理及tomcat指定对应的jdk运行

一、背景 tomcat7启动后&#xff0c;加载jsp页面报错&#xff0c;提示无法将jsp编译为class文件&#xff0c;主要报错信息如下&#xff1a; An error occurred at line: 1 in the generated java file 最后确认该错误原因为&#xff1a;tomcat7不支持jdk1.8版本 机器上已配…

深入剖析大模型在文本生成式 AI 产品架构中的核心地位

一、大模型的崛起与概念解析 在人工智能技术飞速迭代的当下&#xff0c;大模型已成为驱动行业发展的核心引擎。从技术定义来看&#xff0c;大模型&#xff08;Large Model&#xff09; 是指基于深度学习架构、具备海量参数规模&#xff08;通常数十亿至数万亿级别&#xff09;&…

Vue Scoped样式:当动态元素成为“无家可归“的孤儿

引言&#xff1a;一场CSS的"身份危机"想象一下&#xff1a;你精心设计了一个Vue组件&#xff0c;为每个元素添加了漂亮的样式。你满意地添加了scoped属性&#xff0c;确保样式不会"越狱"影响其他组件。然后你动态添加了一些新元素&#xff0c;却发现它们完…

vmware分配了ubuntu空间但是ubuntu没有获取

一开始我看vmware中的ubuntu磁盘空间只有200g不够用&#xff0c;我在vmware给Ubuntu分了300G的磁盘空间&#xff0c;但是ubuntu还是只有之前的200g 如图在ubuntu查看后来发现&#xff0c;在磁盘软件里面需要自己分配磁盘空间大小拓展后就可以了

[MarkdownGithub] 使用块引用高亮显示“注意“和“警告“和其他注意方式的选项

参考来源: https://github.com/orgs/community/discussions/16925 Alerts are an extension of Markdown used to emphasize critical information. On GitHub, they are displayed with distinctive colors and icons to indicate the importance of the content. 提示框是 Ma…

mac测试ollama llamaindex

LlamaIndexs 将大语言模型和外部数据连接在一起的工具。大模型prompt有一个长度限制&#xff0c;当外部知识的内容超过这个长度&#xff0c;无法同时将有效信息传递给大模型&#xff0c;因此就诞生了 LlamaIndex。 具体操作就是通过多轮对话的方式不断提纯外部数据&#xff0c…

数据结构:字符串:大小写转换(changing case of a string)

目录 第一性问题&#xff1a;什么是“大小写”&#xff1f; 逐步构造代码&#xff1a;全部转为大写 我们现在用 第一性原理 的方式&#xff0c;从字符串与字符的本质出发&#xff0c;一步步推导出如何在 C 语言中将字符串中的字母变成全部大写或全部小写。 第一性问题&…

闲庭信步使用图像验证平台加速FPGA的开发:第三十二课——车牌识别的FPGA实现(4)车牌字符的分割定位

&#xff08;本系列只需要modelsim即可完成数字图像的处理&#xff0c;每个工程都搭建了全自动化的仿真环境&#xff0c;只需要双击top_tb.bat文件就可以完成整个的仿真&#xff0c;大大降低了初学者的门槛&#xff01;&#xff01;&#xff01;&#xff01;如需要该系列的工程…

03_java_运行机制

1. java执行流程2. 什么是编译3. 什么是运行

鸿蒙卡片开发保姆级教程

卡片 1. 卡片概念 什么是卡片&#xff1f;卡片用来显示或者提示一些基本信息或者进行一些基本操作。注意不能做重逻辑&#xff0c;所有重要逻辑全部交给应用如果是元服务如何唤醒&#xff1f;因为元服务不提供桌面应用图标&#xff0c;我们可以通过用户手动的方式在桌面上添加一…

反向传播及优化器

反向传播&#xff08;Backpropagation&#xff09;反向传播是计算梯度的算法&#xff0c;核心作用是高效求解 “损失函数对模型所有参数的偏导数”&#xff08;即梯度&#xff09;。没有反向传播&#xff0c;深度学习的大规模训练几乎不可能实现。 整个过程像 “从终点回溯到起…

【机器学习深度学习】生成式模型的评估与验证

目录 前言 1. 主观评估&#xff1a;以人为本的质量判断 1.1 什么是主观评估&#xff1f; 1.2 主观评估的核心流程 1.3 主观评估的优缺点 2. 客观评估&#xff1a;量化的性能衡量 2.1 什么是客观评估&#xff1f; 2.2 常见的客观评估指标 文本生成 图像生成 多模态生…

Linux文件——Ext2文件系统(3)_软硬链接

文章目录文件的软硬链接软链接硬链接软硬链接对比软硬链接应用软硬链接注意事项总结文件的软硬链接 本篇文章将重点讲解文件系统中的一个重要的知识点&#xff1a; 即文件的软硬链接。 软链接 对于软链接的讲解&#xff0c;我们先来使用一个指令看看效果&#xff1a;ln -s 被…

Java SE:类与对象的认识

Java中的类与对象&#xff1a;构建程序世界的基石 在Java编程的世界里&#xff0c;类与对象是面向对象编程&#xff08;OOP&#xff09;的核心概念&#xff0c;它们就像构建大厦的砖瓦&#xff0c;支撑起整个程序的结构。理解类与对象&#xff0c;是掌握Java编程的关键一步。 类…

Hexo - 免费搭建个人博客03 - 将个人博客托管到github,个人博客公开给大家访问

导言我的博客&#xff1a;https://q164129345.github.io/ 既然要将个人博客托管到github&#xff0c;首先我们肯定要有一个github账户。另外也需要在电脑上安装另外一个著名的代码管理工具git。 一、创建github仓库二、在Hexo设置部署的内容# Deployment## Docs: https://hexo.…

一次Oracle集群脑裂问题分析处理

问题描述 填写问题的基础信息。 系统名称 数据库集群 IP地址 xxxxxx 操作系统 Linux 数据库 Oracle 11.2.0.4 症状表现 问题的症状表现如下 4月26号晚22点02分左右&#xff0c;HIS集群发生脑裂&#xff0c;十几分钟后&#xff08;22.18&#xff09;一节点集群率先获…

0基础法考随手笔记 02(刑诉法专题04 辩护与代理)

0基础法考随手笔记 02&#xff08;刑诉法专题04 辩护与代理&#xff09; 1.值班律师相关权力义务2. 3. 4.什么是强制医疗 注意&#xff1a;为强制医疗指派的律师&#xff0c;是诉讼代理人&#xff0c;不是辩护人&#xff0c;因为此人不会被追究刑事责任。 “强制医疗” 是刑事诉…

HF86611_VC1/HF86611Q_VC1:多通道USB HiFi音频解码器固件技术解析

引言随着音频技术的不断发展&#xff0c;多通道音频处理和多接口兼容性成为现代音频设备的重要需求。本文将介绍一款基于XMOS XU316技术的多通道USB HiFi音频解码器固件——HF86611_VC1/HF86611Q_VC1&#xff0c;这是一款专为多接口HiFi音频应用设计的软件解决方案。产品概述HF…

python---列表(List)

文章目录创建列表基本操作访问元素&#xff08;索引&#xff09;切片操作修改列表常用方法列表推导式多维列表列表是 Python 中最基本、最常用的数据结构之一&#xff0c;它是一个有序的可变集合&#xff0c;可以包含不同类型的元素。创建列表 # 空列表 empty_list [] empty_…

ESP32-S3学习笔记<3>:UART的应用

ESP32-S3学习笔记&#xff1c;3&#xff1e;&#xff1a;UART的应用1. 头文件包含2. UART的配置2.1 uart_num的选择2.2 uart_config的设定2.2.1 baud_rate/波特率设置2.2.2 data_bits/数据位数设置2.2.3 parity/奇偶校验位设置2.2.4 stop_bits/停止位设置2.2.5 flow_ctrl/流控位…