当前位置: 首页 > news >正文

Android 网络层最佳实践:Retrofit + OkHttp 封装与实战

📖 目录

  1. 前言

  2. 为什么要封装 Retrofit + OkHttp

  3. 基础封装思路

  4. 支持多 BaseUrl 的设计

  5. 统一响应模型与错误处理

  6. Token 自动刷新机制

  7. 完整网络层结构

  8. 性能优化与调试建议

  9. 结语


💬 前言

在 Android 项目开发中,网络请求几乎是所有业务模块的基础。而在众多方案中,Retrofit + OkHttp 无疑是最稳定、最高效的组合。

它不仅支持注解式接口定义、自动序列化,还能与协程完美结合,轻松实现异步网络通信。
本文将从基础到进阶,带你实现一套「企业级」网络层封装,让你的代码更优雅、更安全、更可维护。


⚙️ 为什么要封装 Retrofit + OkHttp

在小型项目中,直接使用 Retrofit 足够简单;
但随着业务扩展,你可能会遇到以下痛点:

  • 不同模块需要使用 不同的 BaseUrl

  • 接口响应结构不一致,需要统一解析;

  • Token 失效需要自动刷新;

  • 需要统一的异常处理机制;

  • 想让 ViewModel 调用更简洁。

这些问题如果不统一封装,会导致项目结构混乱、维护困难。
因此,我们需要构建一个「高内聚、低耦合」的网络请求框架。


🧱 基础封装思路

Retrofit 是一个「上层封装」,核心依赖 OkHttp:

层级功能说明
OkHttp网络层负责请求发送、拦截、缓存、超时
Retrofit封装层负责接口注解解析、数据转换
协程 + Result安全层负责异常捕获与结果返回

我们将从 OkHttp 开始封装,逐步构建整个网络体系。


🌐 支持多 BaseUrl 的设计

1. 使用场景

在多模块项目中,不同业务接口往往属于不同域名:

模块BaseUrl
用户中心https://user.api.example.com/
支付模块https://pay.api.example.com/
上传模块https://upload.api.example.com/

Retrofit 默认只能设置一个 baseUrl
因此我们需要通过 拦截器 + Header 标识 来动态替换。


2. BaseUrlInterceptor.kt

class BaseUrlInterceptor : Interceptor {companion object {const val HEADER_BASE_URL = "Base-Url" // 自定义 Header 名}override fun intercept(chain: Interceptor.Chain): Response {val request = chain.request()val baseUrlHeader = request.header(HEADER_BASE_URL)// 如果请求头中包含自定义 BaseUrlif (!baseUrlHeader.isNullOrEmpty()) {val newUrl = request.url.newBuilder().scheme("https").host(baseUrlHeader).build()val newRequest = request.newBuilder().url(newUrl).removeHeader(HEADER_BASE_URL) // 使用完后移除.build()return chain.proceed(newRequest)}// 默认请求return chain.proceed(request)}
}

3. RetrofitManager.kt

object RetrofitManager {private const val DEFAULT_BASE_URL = "https://user.api.example.com/"private val okHttpClient by lazy {OkHttpClient.Builder().addInterceptor(BaseUrlInterceptor()).addInterceptor(TokenInterceptor()).addInterceptor(HttpLoggingInterceptor().apply {level = HttpLoggingInterceptor.Level.BODY}).connectTimeout(10, TimeUnit.SECONDS).readTimeout(15, TimeUnit.SECONDS).build()}fun getService(baseUrl: String = DEFAULT_BASE_URL): Retrofit {return Retrofit.Builder().baseUrl(baseUrl).client(okHttpClient).addConverterFactory(GsonConverterFactory.create()).build()}
}

使用示例:

val userApi = RetrofitManager.getService().create(UserApi::class.java)
val payApi = RetrofitManager.getService("https://pay.api.example.com/").create(PayApi::class.java)

🧩 统一响应模型与错误处理

1. 定义统一返回结构

data class BaseResponse<T>(val code: Int,val msg: String?,val data: T?
) {fun isSuccess() = code == 200
}

2. 安全请求封装(协程版)

suspend fun <T> safeApiCall(apiCall: suspend () -> BaseResponse<T>): Result<T> {return try {val response = apiCall()if (response.isSuccess()) {Result.success(response.data!!)} else {Result.failure(Exception(response.msg ?: "未知错误"))}} catch (e: IOException) {Result.failure(Exception("网络连接失败"))} catch (e: HttpException) {Result.failure(Exception("网络错误: ${e.code()}"))} catch (e: Exception) {Result.failure(e)}
}

3. ViewModel 调用示例

class LoginViewModel : ViewModel() {private val _loginState = MutableLiveData<Result<LoginResponse>>()val loginState: LiveData<Result<LoginResponse>> = _loginStatefun login(username: String, password: String) {viewModelScope.launch {val result = safeApiCall {RetrofitManager.getService().create(UserApi::class.java).login(username, password)}_loginState.value = result}}
}

🔑 Token 自动刷新机制

class TokenInterceptor : Interceptor {override fun intercept(chain: Interceptor.Chain): Response {val request = chain.request().newBuilder().addHeader("Authorization", "Bearer ${TokenManager.token}").build()val response = chain.proceed(request)// Token 过期处理if (response.code == 401) {synchronized(this) {val newToken = TokenManager.refreshToken()if (newToken != null) {val newRequest = request.newBuilder().removeHeader("Authorization").addHeader("Authorization", "Bearer $newToken").build()return chain.proceed(newRequest)}}}return response}
}

📦 网络层完整结构

network/
├── ApiService.kt          # 接口定义
├── RetrofitManager.kt     # Retrofit 实例
├── BaseUrlInterceptor.kt  # 多域名支持
├── TokenInterceptor.kt    # Token 刷新
├── NetworkHelper.kt       # 安全请求封装
└── model/└── BaseResponse.kt    # 统一响应模型

⚡ 性能优化与调试建议

优化项建议
⏱️ 超时设置连接 10s,读取 15s,写入 15s
🧠 缓存策略静态接口可添加本地缓存
🔍 日志管理Debug 模式启用 BODY,Release 模式关闭
♻️ 连接池复用默认 Keep-Alive,可减少握手时间
🧩 异常监控在 Result.failure 中上报错误信息

🏁 结语

通过这套封装,我们构建了一个高扩展性、高可维护性的网络层:

层级功能示例
通信层OkHttp超时、缓存、拦截器
封装层Retrofit动态接口映射
逻辑层协程 + Result异常捕获、安全返回
扩展层Token、多 BaseUrl统一管理

🔧 这是一套可以直接落地于实际项目的通用网络架构,既简洁又灵活,适用于 MVVM、MVI 等主流架构。

http://www.dtcms.com/a/494532.html

相关文章:

  • vue3:el-progress
  • 大模型-高效优化技术全景解析:微调 量化 剪枝 梯度裁剪与蒸馏 上
  • Go的http响应数据写入顺序错误,造成实际响应头与预期不一致问题
  • 小型企业网站建设模板找人做jsp网站
  • 【DevOps】基于Nexus3部署Docker内网私有代理仓库docker proxy
  • [嵌入式系统-134]:智能体以及其嵌入式硬件架构
  • 不止于“看”:视频汇聚平台EasyCVR视频监控系统功能特点详解
  • R-切割数据
  • 探秘蚂蚁 S21 XP Immersion 300T:液冷技术如何提升挖矿效能
  • Steps + Input.TextArea 实现弹窗内容
  • 重庆装修公司排名表杭州网站建设优化
  • HarmonyOS应用开发指南:Toast无法显示的完整排查流程与实战案例
  • 【研究生随笔】Pytorch中的线性代数
  • 小米开源端到端语音模型 MiMo-Audio-7B-Instruct 语音智能与音频理解达 SOTA
  • 深度学习进阶(六)——世界模型与具身智能:AI的下一次跃迁
  • RV1106+es8388音频采集和播放调试
  • 【图像超分】论文复现:轻量化超分 | FMEN的Pytorch源码复现,跑通源码,整合到EDSR-PyTorch中进行训练、重参数化、测试
  • 网站设计的公司排名无极电影网首页
  • vue3引入海康监控视频组件并实现非分屏需求一个页面同时预览多个监控视频(3)-接口分页篇(最终版)
  • 新华三H3CNE网络工程师认证—OSPF多区域概念与配置
  • 软件开发商网站html网站用什么空间
  • 免费炫酷网站模板wordpress 模板 破解版
  • Linux1017 shell:awk print printf
  • 服务器对网站的作用有哪些?
  • linux系统编程(十③)RK3568 socket之 TCP 服务器的实现
  • 29、构建可视化日志管理服务器
  • 代码解析:《AGENTREVIEW: Exploring Peer Review Dynamics with LLM Agents》
  • 嵌入式软件面试
  • 安卓前后端连接教程
  • linux系统编程(十③)RK3568 socket之 TCP 服务器的实现【更新客户端断开重连依旧可以收发】