第一个 GET 请求:从定义接口到真正干活
好,咱们终于要发起第一个真实的网络请求了。前面两章讲了 Retrofit 的定位和配置,说白了都是热身。这一章,我带你把一个 GET 请求从零跑到通。
我个人习惯是:先把接口定义写好,再配 Retrofit 实例,最后调用。这三步走完,你的第一个数据就拉回来了。
1. 定义接口:告诉 Retrofit 要干什么
接口是 Retrofit 的“约定”。你用 @GET 注解声明一个方法,Retrofit 就会自动帮你拼出 URL、组装请求。
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(
@Path("user") String user
);
}
注意几点:
@GET里写的是 相对路径,不要写 URL。比如说"users/{user}/repos"就对了。- 花括号
{user}是占位符,后面用@Path动态填值。 - 返回值必须是
Call<T>或者 Retrofit 2.6+ 支持的suspend协程函数。咱们这一章先用Call。
@GET 的路径写成了 https://api.github.com/users/{user}/repos,结果运行时一直报错。千万别把 baseUrl 拼到注解里!
2. 创建 Retrofit 实例:配好“中间人”
接口定义好了,但 Retrofit 还不知道你要用哪个 baseUrl、用什么解析器。所以得先造一个 Retrofit 对象。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
关键字段意思:
| 配置项 | 作用 |
|---|---|
baseUrl | 所有请求的根地址,必须以 / 结尾,否则运行时可能出奇怪的路径拼接问题。 |
addConverterFactory | 告诉 Retrofit 怎么把 JSON 转成 Java 对象。最常用的是 Gson,也可以用 Moshi、Jackson。 |
build() | 造出不可变的 Retrofit 实例。 |
https://api.github.comusers/xxx —— 少了一个 /,服务器直接 404。从那以后我每次写完都检查末尾分隔符。
3. 发起同步/异步调用:数据到手
有了 Retrofit 实例,就能生成接口的实现对象:
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> call = service.listRepos("octocat");
现在 call 只是一个“请求描述”,还没真正发出去。怎么发?两种方式:
同步调用(卡线程)
用 execute() 方法。它会阻塞当前线程直到拿到响应。适合后台线程(比如 RxJava 调度器或协程),不能在主线程调。
new Thread(() -> {
try {
Response<List<Repo>> response = call.execute();
if (response.isSuccessful()) {
List<Repo> repos = response.body();
// 处理数据
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
同步调用的返回值是 Response<T>,你可以拿到 HTTP 状态码、headers、body。我一般用 response.isSuccessful() 判断 2xx 状态码。
异步调用(非阻塞)
用 enqueue() 方法。Retrofit 内部会切换到后台线程执行请求,结果通过回调返回。
call.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
if (response.isSuccessful()) {
List<Repo> repos = response.body();
// UI 线程更新视图
}
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
// 网络异常、解析失败等
}
});
注意了:onResponse 和 onFailure 默认在 主线程 执行,所以你可以在里面直接更新 UI。这是 Retrofit 体贴的地方——省去了手动切线程的麻烦。
完整流程一条龙
为了让你看得更清楚,我画了张流程图。从定义接口到拿到数据,就这几步。
需要特别留意的地方
- Call 只能执行一次:无论是
execute还是enqueue,每个Call对象只能用一次。如果你想重复请求,得通过clone()复制一个新 Call。我曾遇到过复用同一个 Call 导致“already executed”异常,还挺恼火的。 - 关于 baseUrl 的斜杠:再说一遍,
baseUrl末尾一定要加/,不然 Retrofit 会把接口的相对路径当作路径来拼接。这是 Retrofit 的设计哲学——它不会自作主张帮你补斜杠。 - Response 不等于成功:
onResponse回调里拿到的是 HTTP 响应,不代表业务成功。404、500 也会走onResponse,但response.isSuccessful()为 false。只有网络异常、超时、解析失败才会走onFailure。
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)),就能在 Logcat 里看到完整的请求 URL、请求头和响应体。我每次写新接口都会先开这个,看一眼 URL 拼对了没。
代码跑通了,然后呢?
这一章的内容其实已经够你用 Retrofit 发起第一个真实请求了。定义接口、创建实例、调用——三部曲很清晰。以后你会碰到更多注解,比如 @Query、@Body、@Header,但核心套路不变。
嗯,说实话,我第一次用 Retrofit 时觉得“怎么比 OkHttp 多那么多步骤”,但用顺手后真香——代码干净、测试方便、类型安全。希望你也尽快进入“真香”状态。