第2章:OkHttp入门:库配置、同步与异步请求、Get请求实战

好,咱们正式开始搞网络请求了。

Android开发里,网络请求是家常便饭。我记得刚入行那会儿,用的还是HttpURLConnection,写起来那叫一个痛苦。后来OkHttp一出来,我几乎是第一时间就换上了。为什么?因为它设计得确实漂亮,用起来顺手,性能也靠谱。

这一章,咱们就好好聊聊OkHttp。我会从最基础的库配置讲起,然后带你写一个真正的Get请求。同步、异步我都会讲,你想想看,这两种方式在实际项目中该怎么选?

2.1 OkHttp是什么?为什么选它?

OkHttp,说白了就是一个高效的HTTP客户端库。它由Square公司开发,现在已经是Android开发的事实标准了。

我个人习惯用OkHttp,原因有三:

  • 连接池复用:默认支持HTTP/2和连接池,能减少请求延迟。我在项目中遇到过,如果不做连接复用,频繁创建连接会非常慢。
  • 自动重试:当连接失败时,OkHttp会自动重试。嗯,这里要注意,重试机制虽然好,但幂等性你得自己保证。
  • 拦截器机制:这个太强了。你可以加日志拦截器、加缓存拦截器、加Header拦截器。我曾经用拦截器统一处理了Token过期刷新,省了不少事。

核心概念:OkHttp的核心是OkHttpClient和Call。OkHttpClient是全局配置,Call代表一次具体的请求。

2.2 依赖配置:三步搞定

配置OkHttp非常简单。你只需要在build.gradle里加一行依赖就行。

// 在 app/build.gradle 的 dependencies 块里添加
implementation 'com.squareup.okhttp3:okhttp:4.12.0'

等等,这里有个坑。我记得有一次,我同事直接复制了最新版本号,结果项目编译报错。为什么?因为OkHttp从4.x开始,最低支持API 21(Android 5.0)。如果你的项目minSdk低于21,就得用3.x版本。

OkHttp版本 最低API级别 推荐场景
4.x API 21+ 新项目,minSdk >= 21
3.x API 9+ 老项目兼容,或minSdk较低

小提示:如果你用Kotlin,建议直接用4.x。Kotlin协程配合OkHttp,写起来非常舒服。

2.3 同步请求 vs 异步请求

这是新手最容易搞混的地方。我简单解释一下:

  • 同步请求:调用后,当前线程会阻塞,直到拿到结果。说白了,就是“死等”。
  • 异步请求:调用后,立即返回。结果通过回调通知你。说白了,就是“你先忙,有结果了我告诉你”。

你想想看,如果在主线程里做同步请求,会怎么样?对,ANR(应用无响应)。所以,同步请求必须在子线程里执行。异步请求则没有这个限制,回调会在子线程里执行。

警告:千万不要在主线程执行同步网络请求!我曾经见过一个新手,直接在Activity的onCreate里写同步请求,结果应用启动就卡死。嗯,血的教训。

2.4 Get请求实战:手写一个例子

光说不练假把式。咱们直接写代码。

第一步:创建OkHttpClient

我习惯把OkHttpClient做成单例,因为它是线程安全的,而且可以复用连接池。

// 全局只创建一个实例
OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .build();

第二步:构建请求

Request request = new Request.Builder()
        .url("https://api.github.com/users/octocat")
        .get()  // 默认就是GET,可以省略
        .build();

第三步:执行请求(同步方式)

// 必须在子线程执行
new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                String body = response.body().string();
                // 这里拿到数据,可以更新UI(记得切回主线程)
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();

第四步:执行请求(异步方式)

client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // 请求失败,比如网络不通
        e.printStackTrace();
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful()) {
            String body = response.body().string();
            // 注意:这里是在子线程,更新UI需要切回主线程
        }
    }
});

关键点:异步请求的onResponse回调是在子线程执行的。如果你要更新UI,记得用runOnUiThread或者Handler切回主线程。

2.5 避坑指南:我踩过的那些坑

OkHttp虽然好用,但有些细节不注意,还是会出问题。我分享几个亲身经历:

  • Response.body().string()只能调用一次:为什么?因为body是一个流,读取一次后就关闭了。我曾经在调试时连续调了两次,第二次直接返回空字符串。嗯,这个坑我印象很深。
  • 记得关闭Response:虽然OkHttp会帮你管理连接,但Response的body在使用完后最好关闭。用try-with-resources最安全。
  • 超时设置别忘:默认超时是10秒,但如果你在弱网环境下,建议适当延长。我一般设30秒。

个人习惯:我写网络请求时,一定会加日志拦截器。这样出了问题,看一眼日志就知道请求发了什么、返回了什么。推荐用HttpLoggingInterceptor。

2.6 小结

这一章,咱们把OkHttp的入门知识过了一遍。从依赖配置到同步异步请求,再到实战Get请求,你应该已经能上手了。

下一章,我会讲Post请求和文件上传。到时候咱们再深入聊聊请求体的构建。嗯,先消化这一章的内容,动手写几个例子试试。

记住,网络请求是Android开发的基石。把OkHttp玩熟了,后面的路就好走了。