第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玩熟了,后面的路就好走了。