Retrofit基本使用与常用注解

Retrofit 这玩意儿,说白了就是一个把 HTTP 请求封装成 Java 接口的工具。你不需要手动拼 URL、写 HttpURLConnection,只需要在接口上加几个注解,它就能自动把请求发出去,再把响应解析成你想要的 Java 对象。

我最早接触 Retrofit 的时候,觉得它不过是个封装好的网络库。后来在实际项目里重构了一堆网络代码,才发现它的注解系统才是真正的灵魂。那咱们今天就聊聊这些核心注解怎么用。

一个最简单的请求怎么搭

先搭个最简单的架子。我习惯把这个步骤分成三步:

  1. 写一个接口,里面定义好你要调用的 API 方法。
  2. 创建 Retrofit 实例,告诉它 base URL 和转换器(比如 Gson)。
  3. 拿到接口实例,然后直接调用方法。

举个栗子,我要请求 GitHub 的用户信息,URL 是 https://api.github.com/users/octocat。那么接口可以写成:

public interface GitHubService {
    @GET("users/{username}")
    Call<User> getUser(@Path("username") String username);
}

看到 @GET 了吗?它告诉 Retrofit 这是个 GET 请求。@Path 注解把 {username} 替换成你传入的参数值。

然后构造 Retrofit 实例:

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();

GitHubService service = retrofit.create(GitHubService.class);
Call<User> call = service.getUser("octocat");

嗯,这里要注意,baseUrl 必须以 / 结尾,否则 Retrofit 会报奇怪的错误。我踩过这个坑,调试了半天才发现是少了个斜杠。

常用注解逐个聊

@GET / @POST / @PUT / @DELETE

这些注解代表请求方法。你写 @GET,Retrofit 就知道发 GET 请求。同理,@POST 用于提交数据。@PUT 用于全量更新,@DELETE 用来删除资源。

我个人习惯在接口上直接写明方法类型,这样代码一看就懂。比如:

@POST("users")
Call<User> createUser(@Body User user);

@DELETE("users/{id}")
Call<Void> deleteUser(@Path("id") int userId);

路径替换:@Path

@Path 用来替换 URL 中的占位符 {xxx}。你想想看,如果 API 里用户 ID 是路径的一部分,用 @Path 最方便。我在项目里经常遇到这样的 RESTful 接口:

@GET("api/v1/orders/{orderId}")
Call<Order> getOrder(@Path("orderId") String orderId);

注意:@Path 的参数值会被 URL 编码。如果参数里包含特殊字符,比如中文或空格,Retrofit 会自动帮你转义,这点很省心。

查询参数:@Query

很多 GET 接口后面跟着一长串查询参数,比如 ?page=1&size=20。这时候用 @Query:

@GET("users")
Call<List<User>> searchUsers(@Query("name") String name,
                              @Query("page") int page);

它会自动拼装成 /users?name=xxx&page=1。如果你有多个查询参数,直接加多个 @Query 就行。也可以用一个 Map:

@GET("users")
Call<List<User>> searchUsers(@QueryMap Map<String, String> options);

我曾经在一个分页列表里遗漏了 @Query,结果接口每次都返回第一页数据。排查发现是参数没传进去,补上注解就好了。

POST 请求的请求体:@Body

如果你要提交 JSON 数据,用 @Body 注解。Retrofit 会自动把对象转成 JSON(前提是你配了 Gson 或 Moshi 转换器)。示例:

@POST("users")
Call<User> createUser(@Body User user);

这里要注意,@Body 不能为 null,否则 Retrofit 会抛异常。我习惯在调用前做一次判空处理。

动态路径和查询:组合使用

实际项目中经常需要路径和查询参数并存。比如:

@GET("products/{category}")
Call<List<Product>> getProductsByCategory(@Path("category") String category,
                                              @Query("sort") String sort,
                                              @Query("page") int page);

这样就会请求 /products/electronics?sort=price&page=1。

表:常用注解速查

注解用途参数位置示例
@GETGET 请求方法上@GET("user/{id}")
@POSTPOST 请求方法上@POST("user")
@PUTPUT 请求方法上@PUT("user/{id}")
@DELETEDELETE 请求方法上@DELETE("user/{id}")
@Path替换路径占位符方法参数@Path("id") int id
@Query添加查询参数方法参数@Query("page") int page
@QueryMap批量查询参数方法参数@QueryMap Map params
@BodyPOST/PUT 请求体方法参数@Body User user
@Headers设置固定请求头方法上@Headers("Authorization: Bearer xxx")
@Header动态请求头方法参数@Header("Authorization") String
避坑指南:我曾经在一个老项目里看到有人把 @Query 写成了 @Path,结果接口一直 404。记住:路径变量用 @Path,查询参数用 @Query。千万别搞混。

关于 @Headers 和 @Header

有些接口需要固定的 header,比如 Content-Type。你可以在方法上直接加 @Headers:

@Headers("Content-Type: application/json")
@POST("upload")
Call<ResponseBody> upload(@Body RequestBody body);

如果 header 的值是动态的(比如 ),就用 @Header 注解参数:

@POST("secure/data")
Call<Data> getData(@Header("Authorization") String );

我个人更喜欢把 这样的全局信息放在拦截器里统一添加,而不是每个方法都传一次参数。后面讲拦截器的时候会细说。

整个调用流程

咱们把上面这些串起来,画一张图看看 Retrofit 是怎么工作的。

Retrofit 注解驱动请求流程 定义接口 + 注解 创建 Retrofit 实例 创建接口实例 调用方法(同步/异步) Retrofit 解析注解构建请求 注解解析示例 @GET("users/{id}") @Path("id") → 替换占位符 @Query("page") → 拼接到 ? @Body → JSON 序列化 最终 HTTP 请求 GET /users/octocat?page=1 Host: api.github.com Content-Type: application/json (若有 @Body 则含请求体)
个人建议:刚开始学 Retrofit 的时候,不要一上来就折腾拦截器、缓存。先把 @GET、@POST、@Path、@Query 这几个玩熟。我当年就是基础不牢,写出来的接口各种拼错 URL,后来回头补课才踏实。

关于 @QueryMap 的坑

如果你有一堆不确定的查询参数,用 @QueryMap 确实方便。但要注意,Map 的 key 和 value 都必须是 String,否则 Retrofit 会报类型转换异常。我曾经传了个 Integer 进去,直接 crash 了。正确做法:

Map<String, String> params = new HashMap<>();
params.put("page", String.valueOf(1));
params.put("size", String.valueOf(20));
Call<List<Product>> call = service.getProducts(params);

小结一下

Retrofit 的注解系统其实不复杂。记住几点:

  • 方法上写请求类型(@GET / @POST 等)和路径
  • 路径里的动态部分用 @Path
  • 查询参数用 @Query 或 @QueryMap
  • POST 请求体用 @Body
  • 请求头用 @Headers 或 @Header

这些基础打好了,后面聊拦截器和缓存的时候你才能游刃有余。嗯,今天就到这儿,你现在可以打开 IDE 写几个接口试试了。