1. 引言:网络请求在 Android 中的角色

在移动互联网时代,一个没有网络能力的 App 就像是一座孤岛。无论是刷 B 站视频、看头条新闻,还是在玩安卓(WanAndroid)上收藏文章,本质上都是手机客户端与远程服务器之间的数据交换

为了高效地完成这种交换,Android 开发者通常使用 OkHttp 作为底层引擎,使用 Retrofit 作为高级指挥官。本文将带你从 0 开始,彻底掌握这两个库。


2. 底层基石:OkHttp 详解

OkHttp 是一个高效的 HTTP 客户端。它的职责很纯粹:建立连接、发送请求、接收数据。

一个标准的 OkHttp 请求涉及四个核心对象:

  1. OkHttpClient:相当于“快递公司”。它内部维护了线程池和连接池,非常耗资源,全局建议只创建一个实例

  2. Request:相当于“快递单”。上面写明了目的地(URL)、寄送方式(GET/POST)以及包裹备注(Header)。

  3. Call:相当于“投递动作”。由快递公司根据快递单生成的任务。

  4. Response:相当于“回执包裹”。里面装有服务器返回的状态码和具体数据(Body)。

    // 1. 初始化快递公司:使用 Builder 模式配置各种参数
    val client = OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS) // 设置连接超时为 10 秒
        .build()
    
    // 2. 填写快递单
    val request = Request.Builder()
        .url("https://www.wanandroid.com/article/list/0/json") // 目标服务器地址
        .get() // 默认就是 GET 方式,获取数据
        .addHeader("User-Agent", "Android_Client") // 告诉服务器我是谁,防止被拦截
        .build()
    
    // 3. 产生投递任务并异步发送
    client.newCall(request).enqueue(object : Callback {
        // 【知识点】Callback 是一个接口,成功或失败都会回调它
        // enqueue 表示异步,不会卡死手机屏幕
        
        override fun onFailure(call: Call, e: IOException) {
            // 网络断了或者服务器崩了会走这里
            Log.e("Network", "请求彻底失败: ${e.message}")
        }
    
        override fun onResponse(call: Call, response: Response) {
            // 只要服务器有回应(哪怕是 404)都会走这里
            response.use {
                if (!it.isSuccessful) return // 状态码不是 200~299 就算异常
                
                // 【关键】body?.string() 只能调用一次!调用后流会关闭
                val jsonString = it.body?.string()
                Log.d("Network", "获取到的原始 JSON 数据: $jsonString")
            }
        }
    })

    3. 进阶指挥官:Retrofit 详解

    既然 OkHttp 已经能发请求了,为什么还要 Retrofit?
    痛点:OkHttp 返回的是字符串,我们需要手动写解析逻辑;且当接口有几十个时,代码会变得极其混乱。
    Retrofit 价值:它通过注解动态代理技术,把网络请求变成了像“调用本地方法”一样简单。

    Retrofit 要求你先定义一个“接口类”,把 URL 路径映射成函数。

/**
 * 第一步:定义数据类(Bean/Entity)
 * 根据服务器返回的 JSON 结构,利用 GSON 插件自动生成
 */
data class WanArticleResponse(
    val data: DataDetail,
    val errorCode: Int,
    val errorMsg: String
)

/**
 * 第二步:定义服务接口
 */
interface ApiService {
    // @GET 后面跟的是 baseUrl 之后的剩余路径
    @GET("article/list/{page}/json")
    fun getHomeList(@Path("page") page: Int): Call<WanArticleResponse>
}
// 1. 创建 Retrofit 实例
val retrofit = Retrofit.Builder()
    .baseUrl("https://www.wanandroid.com/") // 基础域名,必须以 / 结尾
    .client(client) // 【关联】把上面的 OkHttp 装进来
    .addConverterFactory(GsonConverterFactory.create()) // 【自动解析】JSON 转对象
    .build()

// 2. 生成接口的实现类
val service = retrofit.create(ApiService::class.java)

// 3. 调用函数
service.getHomeList(0).enqueue(object : retrofit2.Callback<WanArticleResponse> {
    override fun onResponse(call: Call<WanArticleResponse>, response: retrofit2.Response<WanArticleResponse>) {
        // 此时 response.body() 已经是解析好的对象了,不再是字符串!
        val articles = response.body()?.data
        println("第一篇文章标题:${articles?.datas?.get(0)?.title}")
    }

    override fun onFailure(call: Call<WanArticleResponse>, t: Throwable) {
        // 异常处理
    }
})

4.可能出现的问题

Android 默认禁止联网!你必须在 AndroidManifest.xml 中手动声明:

android:usesCleartextTraffic="true"

如果是 HTTP 而不是 HTTPS 链接,还要开启:

android:usesCleartextTraffic="true"

规则:网络请求必须在“子线程”,UI 更新必须在“主线程”。

  • OkHttp 的 enqueue 自动帮你开了子线程。

  • 但在 onResponse 回调里,你不能直接操作 textView.text = xxx。

  • 解决方法:使用 runOnUiThread { ... } 或者结合 Jetpack 的 LiveData。

在 build.gradle 的 dependencies 里,至少要引入这三项:

implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // Retrofit 专用 JSON 解析器

5. 总结:如何构建一个完美的网络层

一个成熟的 Android 开发项目,通常会这样封装:

  1. 单例模式:全局只创建一个 ApiService 实例。

  2. 拦截器配置:在 OkHttp 中添加拦截器(Interceptor),用于自动打印日志或在 Header 中统一添加 Token。

  3. 异常统一处理:通过封装一层 Result 类,统一处理网络超时、404 等错误。

网络请求是 Android 开发的地基。只有理解了 OkHttp 的快递模型和 Retrofit 的映射逻辑,你才能在面对复杂的业务需求时游刃有余。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐