OkHttp 与 Retrofit 完美结合:打造高效的 Android 网络请求

前言

在现代 Android 开发中,网络请求是几乎每个应用都必不可少的功能。OkHttp 和 Retrofit 作为当前最流行的网络请求库组合,为开发者提供了简洁高效的解决方案。本文将详细介绍如何将这两者结合使用,充分发挥它们的优势。

一、OkHttp 和 Retrofit 简介

1. OkHttp

OkHttp 是一个高效的 HTTP 客户端,具有以下特点:

  • 支持 HTTP/2,允许所有请求共享同一个 socket

  • 连接池减少请求延迟

  • 透明的 GZIP 压缩

  • 响应缓存避免重复网络请求

  • 自动处理网络问题,支持请求重试

2. Retrofit

Retrofit 是一个基于 OkHttp 的 RESTful HTTP 网络请求框架,它:

  • 通过接口和注解配置网络请求

  • 支持多种数据解析方式(Gson、Jackson、Moshi 等)

  • 支持 RxJava 和 Coroutines

  • 将 HTTP API 转换为 Java/Kotlin 接口

二、基本集成与使用

1. 添加依赖

首先在 build.gradle 中添加依赖:

implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // Gson 转换器

2. 创建 Retrofit 实例

val okHttpClient = OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).build()val retrofit = Retrofit.Builder().baseUrl("https://api.example.com/").client(okHttpClient).addConverterFactory(GsonConverterFactory.create()).build()

3. 定义 API 接口

interface ApiService {@GET("users/{id}")suspend fun getUser(@Path("id") userId: String): User@POST("users")suspend fun createUser(@Body user: User): Response<Unit>@GET("users")suspend fun getUsers(@Query("page") page: Int): List<User>
}

4. 发起网络请求

val apiService = retrofit.create(ApiService::class.java)// 使用协程
lifecycleScope.launch {try {val user = apiService.getUser("123")// 处理 user 数据} catch (e: Exception) {// 处理异常}
}

三、高级功能与配置

1. 添加公共请求头和参数

通过 OkHttp 的拦截器实现:

val okHttpClient = OkHttpClient.Builder().addInterceptor { chain ->val originalRequest = chain.request()val requestWithHeaders = originalRequest.newBuilder().header("Authorization", "Bearer token").header("Accept", "application/json").method(originalRequest.method, originalRequest.body).build()chain.proceed(requestWithHeaders)}.addInterceptor(HttpLoggingInterceptor().apply {level = HttpLoggingInterceptor.Level.BODY}).build()

2. 缓存配置

val cacheSize = 10 * 1024 * 1024 // 10 MB
val cache = Cache(File(context.cacheDir, "httpCache"), cacheSize.toLong())val okHttpClient = OkHttpClient.Builder().cache(cache).addInterceptor { chain ->val request = chain.request()val response = chain.proceed(request)val cacheControl = CacheControl.Builder().maxAge(1, TimeUnit.HOURS).build()response.newBuilder().header("Cache-Control", cacheControl.toString()).build()}.build()

3. 文件上传与下载

文件上传:

@Multipart
@POST("upload")
suspend fun uploadFile(@Part file: MultipartBody.Part,@Part("description") description: RequestBody
): Response<UploadResponse>// 使用示例
val file = File(filePath)
val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), file)
val part = MultipartBody.Part.createFormData("file", file.name, requestFile)
val description = "This is a test file".toRequestBody()apiService.uploadFile(part, description)

文件下载:

@Streaming
@GET
suspend fun downloadFile(@Url fileUrl: String): Response<ResponseBody>// 使用示例
val response = apiService.downloadFile("https://example.com/file.zip")
if (response.isSuccessful) {val inputStream = response.body()?.byteStream()// 保存文件
}

4. 错误统一处理

val okHttpClient = OkHttpClient.Builder().addInterceptor { chain ->val request = chain.request()val response = chain.proceed(request)when (response.code) {401 -> {// 处理未授权throw UnauthorizedException()}404 -> {// 处理未找到throw NotFoundException()}in 500..599 -> {// 处理服务器错误throw ServerException()}else -> response}}.build()

四、最佳实践

  1. 单例模式:Retrofit 和 OkHttpClient 的创建成本较高,应该使用单例模式

  2. 合理配置超时时间:根据应用需求设置连接、读取和写入超时

  3. 日志拦截器:在 debug 版本中添加日志拦截器方便调试

  4. 错误处理:统一处理网络错误和业务错误

  5. 进度监听:对于大文件上传下载,实现进度监听

  6. HTTPS 安全配置:正确配置 HTTPS 证书验证

五、完整示例代码

object RetrofitClient {private const val BASE_URL = "https://api.example.com/"private val okHttpClient by lazy {OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).addInterceptor(HttpLoggingInterceptor().apply {level = if (BuildConfig.DEBUG) {HttpLoggingInterceptor.Level.BODY} else {HttpLoggingInterceptor.Level.NONE}}).addInterceptor { chain ->val originalRequest = chain.request()val request = originalRequest.newBuilder().header("Authorization", "Bearer ${getToken()}").header("Accept", "application/json").method(originalRequest.method, originalRequest.body).build()chain.proceed(request)}.build()}private val retrofit by lazy {Retrofit.Builder().baseUrl(BASE_URL).client(okHttpClient).addConverterFactory(GsonConverterFactory.create()).build()}val apiService: ApiService by lazy {retrofit.create(ApiService::class.java)}private fun getToken(): String {// 从 SharedPreferences 或其他地方获取 tokenreturn ""}
}// 使用示例
lifecycleScope.launch {try {val users = RetrofitClient.apiService.getUsers(page = 1)// 更新 UI} catch (e: Exception) {// 处理错误}
}

六、总结

OkHttp 和 Retrofit 的结合为 Android 网络请求提供了强大而灵活的解决方案。OkHttp 负责底层的网络通信,而 Retrofit 则提供了更高层次的抽象,使网络请求的代码更加简洁和易于维护。通过合理配置和扩展,可以满足各种复杂的网络请求需求。

在实际项目中,我们可以根据具体需求进一步扩展,例如添加请求重试机制、自定义数据解析器、集成 RxJava 或 Coroutines 等。掌握这两者的结合使用,将大大提高 Android 应用的网络请求效率和代码质量。

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

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

相关文章

系统辨识建模

系统辨识建模 一、系统辨识建模的作用 1. 建立真实物理系统的数学模型 2. 为后续控制器/强化学习算法提供仿真环境 3. 提高控制精度和安全性 二、本文的系统辨识是怎么做的 1. 实验采集 2. 数学建模 3. 在控制系统中的作用 三、实际用法流程(简化版) 1. 系统辨识阶段 2. 强化…

Android开发:Java与Kotlin深度对比

1. 语言特性与现代性 Java (特别是 Android 主要使用的 Java 8 及之前版本): 相对冗长&#xff1a; 需要编写更多的样板代码&#xff08;如 getter/setter、findViewById 的显式类型转换、匿名内部类等&#xff09;。空指针异常 (NPE)&#xff1a; 类型系统默认允许 null&#…

米家打印机驱动:Wi-Fi 无线打印丝滑顺畅不卡顿,从此告别对打印机干瞪眼

各位小米家居控们&#xff0c;你们有没有过这种经历&#xff0c;新买的打印机回家&#xff0c;结果电脑跟它像俩傲娇的小情侣&#xff0c;死活不搭话&#xff1f;急得你想当场表演一个“打印机抱头痛哭”&#xff1f;别急&#xff0c;今天就给你们安利个神队友——米家打印机驱…

日语学习-日语知识点小记-构建基础-JLPT-N3阶段(7):自動詞 & 他動詞

日语学习-日语知识点小记-构建基础-JLPT-N3阶段&#xff08;7&#xff09;&#xff1a;自動詞 &#xff06; 他動詞1、前言&#xff08;1&#xff09;情况说明&#xff08;2&#xff09;工程师的信仰2、知识点&#xff08;&#xff11;&#xff09;自動詞 &#xff06; 他動…

深入理解设计模式:访问者模式详解

在软件开发中&#xff0c;我们经常会遇到需要对一个复杂对象结构进行操作的情况。随着需求的不断变化&#xff0c;我们可能需要在这个对象结构上添加各种新的操作。如果直接在对象结构中添加这些操作&#xff0c;会导致类的职责过重&#xff0c;且每次添加新操作都需要修改原有…

Linux timerfd 定时器封装

使用 timerfd epoll() 实现&#xff0c;简洁精确。没定义 MU_ERROR 宏的话替换为 printf 即可。mu_timer.h:#ifndef _MU_TIMER_H_ #define _MU_TIMER_H_#ifdef __cplusplus extern "C" { #endif#include <stdint.h> #include <time.h> #include <pth…

【样式效果】Vue3实现仿制iOS按钮动态效果

iOS开关效果定义变量&#xff1a; <style scoped lang"scss">.layout {// 按钮宽度$button-width: 500px;// 按钮高度$button-height: 250px;// 按钮里面圆形直径$circle-diameter: 200px;// 按钮背景与里面圆形间距$button-circle-offset:calc(($button-he…

京东疯狂投资具身智能:众擎机器人+千寻智能+逐际动力 | AI早报

每日分享全球最新AI资讯【应用商业八卦技术】&#xff0c;&#x1f30f;&#xff1a;未来世界2099应用 1、马斯克推出儿童AI"Baby Grok"引热议&#xff1a;安全性能否经受考验&#xff1f; 2、蚂蚁AQ健康应用霸榜苹果商店&#xff0c;或将联手Apple Watch打造智能健康…

Jiasou TideFlow AIGC SEO Agent:全自动外链构建技术重构智能营销新标准

AI时代SEO技术革命&#xff1a;企业如何突破流量增长瓶颈&#xff1f;随着Google算法升级至MUM模型&#xff0c;传统SEO工具已难以应对多模态内容优化需求。在搜索引擎日均处理120亿次查询的生态中&#xff0c;企业官网平均自然流量转化周期长达6-8个月&#xff0c;因此诸如Jia…

Docker-compose:服务编排

Docker-compose 介绍 服务编排:按照一定的业务规则批量管理容器 在微服务架构的应用系统中,一般包含 N 个微服务,且每个微服务一般都会部署多个实例。此时,如果每个微服务都要手动启停,维护的工作量会很大。 要从 Dockerfile build image 或者去 docker hub 拉取 image …

异地服务器备份Mysql数据

前言异地服务器备份Mysql数据即Mysql的server端与备份服务器不是同一个。Mysql服务端安装在192.168.3.36中&#xff0c;现在需要在IP为192.168.209.129的服务器中使用mysqldump命令备份指定数据库数据;192.168.209.129没有装过Mysql客户端;1.安装Mysql客户端不安装Mysql客户端就…

NGINX 高级配置解析:`proxy_request_buffering` 使用详解

在使用 NGINX 作为反向代理服务器时&#xff0c;处理客户端请求体&#xff08;如上传文件或大体积 POST 请求&#xff09;的方式会直接影响应用性能与资源使用。其中&#xff0c;proxy_request_buffering 是一个非常关键但容易被忽略的配置项。 本文将详细介绍该指令的作用、典…

增加交叉验证和超参数调优

前文中&#xff0c;只是给了基础模型&#xff1a; PyTorch 实现 CIFAR-10 图像分类&#xff1a;从数据预处理到模型训练与评估-CSDN博客 今天我们增加交叉验证和超参数调优&#xff0c; 先看运行结果&#xff1a; 在测试集上评估最终模型 最终模型在测试集上的准确率&…

解决pip指令超时问题

用pip指令&#xff0c;在安装Django3.2时报错&#xff0c;询问ChatGpt后得到的解决方案pip 下载超时 —— 是 当前网络连接到 PyPI 官方源太慢或不稳定&#xff0c;甚至可能连不上了&#xff0c;而 pip 默认的超时时间又太短&#xff0c;就导致了中途失败&#xff1a;ReadTimeo…

Oracle定时清理归档日志

线上归档日志满了&#xff0c;系统直接崩了&#xff0c;为解决这个问题&#xff0c;创建每月定时清理归档日志。 创建文件名 delete_archivelog.rman CONFIGURE ARCHIVELOG DELETION POLICY CLEAR; RUN {ALLOCATE CHANNEL c1 TYPE DISK;DELETE ARCHIVELOG ALL COMPLETED BEFORE…

ELF 文件操作手册

目录 一、ELF 文件结构概述 二、查看 ELF 文件头信息 1、命令选项 2、示例输出 3、内核数据结构 三、ELF 程序头表 1、命令选项 2、示例输出 3、关键说明 4、内核数据结构 四、ELF 节头表详解 查看节头表信息 1、命令选项 2、示例输出 3、标志说明 4、重要节说…

深入浅出Python函数:参数传递、作用域与案例详解

&#x1f64b;‍♀️ 博主介绍&#xff1a;颜颜yan_ ⭐ 本期精彩&#xff1a;深入浅出Python函数&#xff1a;参数传递、作用域与案例详解 &#x1f3c6; 热门专栏&#xff1a;零基础玩转Python爬虫&#xff1a;手把手教你成为数据猎人 &#x1f680; 专栏亮点&#xff1a;零基…

ps aux 和 ps -ef

在 Linux/Unix 系统中&#xff0c;ps aux 和 ps -ef 都是用于查看进程信息的命令&#xff0c;结合 grep node 可以筛选出与 Node.js 相关的进程。它们的核心功能相似&#xff0c;但在输出格式和选项含义上有区别&#xff1a;1. 命令对比命令含义主要区别ps auxBSD 风格语法列更…

Spark ML 之 LSH

src/test/scala/org/apache/spark/ml/feature/BucketedRandomProjectionLSHSuite.scala test("approxSimilarityJoin for self join") {val data = {for (i <- 0 until 24) yield Vectors

关键成功因素法(CSF)深度解析:从战略目标到数据字典

关键成功因素法由John Rockart提出&#xff0c;用于信息系统规划&#xff0c;帮助企业识别影响系统成功的关键因素&#xff0c;从而确定信息需求&#xff0c;指导信息技术管理。该方法通过识别关键成功因素&#xff0c;找出关键信息集合&#xff0c;确定系统开发优先级&#xf…