Restful风格接口基本成了业界主流,Retrofit框架也大火特火,最近项目中也决定更新换代,采用Retrofit。本着学习之余,也对接下来的学习者有一些帮助,于是写了本文,主要的内容是对官网内容的一个翻译和补充解释。
plus:本文假设你对于基本的HTTP协议有所了解。
一、Retrofit简介
Retrofit内部使用OKhttp来进行网络请求, 会把网络请求转化为一个java接口,使用了编译阶段的注解提高开发效率。如下,在开发中把网络请求定义在一个专门的java接口中
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
通过Retrofit为此接口生成一个实现,代码如下
//定制OKHttpClient
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.connectTimeout(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.writeTimeout(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.build();
//实例化 Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.client(okHttpClient)
.build();
//生成实现类
GitHubService service = retrofit.create(GitHubService.class);
通过生成的GitHubService,开发者可以使用同步或者异步的方式去请求网络接口。
Call<List<Repo>> repos = service.listRepos("octocat");
Retrofit 使用注解来描述HTTP接口,提升开发效率,它有如下特性:
- URL参数动态替换、动态地址栏参数。
- 对象能动态转化成RequestBody,比如 JSON和protocol buffers。
- 支持Multipart RequestBody(对这个不了解的,看下这篇博文)
- 支持文件上传。
上述特性,具体看下面的章节就明白了。
二、Retrofit的注解用法详解
1. 网络接口的声明
在Retrofit中,每个网络接口都必须有一个注解,网络接口上的注解表明了类型、Url访问路径。这里有五个内建的注解: GET, POST, PUT, DELETE, and HEAD。如下示例,声明了一个简单的GET网络接口,其相对路径是users/list。
@GET("users/list")
跟传统一样,你可以在路径中加上参数。
@GET("users/list?sort=desc")
2. URL相关的注解
相对路径中可以声明动态参数,用 {str1} 代码 表示,在接口里面通过 @Path("str1") 修饰相应用于动态替换的参数。
具体用法如下展示,其中groupId的值会动态替换掉访问路径中的{id}。
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
地址栏参数也是可以使用 @Query("str")加上,效果就是在访问URL后面动态加上 @Query("str")标识的参数
如下方法,最终的URL会是这样:group/{id}/users/?sort=xxx
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
如果是想加上很多个地址栏参数,Retrofit提供了map的方式,map里面的多个键值对会依次加入到URL后边。
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
3. Request Body 相关注解
上文已经提到,对象能动态转化成RequestBody,具体是要在对象前使用 @Body注解。如下代码所示,User对象会被转化成Body。
@POST("users/new")
Call<User> createUser(@Body User user);
The object will also be converted using a converter specified on the Retrofit instance. If no converter is added, only RequestBody can be used.
对象转化为Body的方式是Retrofit默认提供的一个转化器,你也可以自己创建一个转换器,在Retrofit实例化的时候进行指定。
4. 表单和使用Multipart Body
Retrofit使用注解 @FormUrlEncoded 来表示使用表单,表单里面相应的字段在接口参数前使用 @Field("XXX")标识,括号里面是key值。
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
Multipart Body直接使用 @Multipart 在接口方法上标识. Body中的Parts 直接使用 @Part 标识。
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
同上文所说,Multipart parts也采用了Retrofit默认的序列化转换器,如果你希望自己定义序列化,可以继承RequestBody类,重写序列化方法。
5. Retrofit设置请求头的相关注解
你可以为一些方法设定请求头字段,这个需使用 @Headers 注解
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
请求头字段也可以被动态改变,在接口参数前加上 @Header就可以了。
额外说明:如果该参数传入为null,那么请求头的该字段会被删除。该字段的参数类型可以不是String类型,Retrofit最终会调用该参数的toString()方法,得到的值作为请求头该字段的值。
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
一路看下来,可能有读者会问了,难道我需要为每个接口方法都设置一遍请求头吗?
不是的,对于所有接口都要用到的请求头,可以通过 Okhttp拦截器统一设置。
三、Retrofit 的配置
通过上述描述,大家应该已经发现,Retrofit提供的功能就是把网络请求变成一个可调用的实例对象,这个对象里面是Restful风格的各个网络请求接口。Retrofit提供了一些好的注解,帮我们减轻了封装网络模块的工作。
Retrofit默认会为我们的平台提供合适的,健壮的默认配置,但是这些配置我们也是可以自己定制的。
默认情况下,Retrofit 只能 把 HTTP Body类型 反序列化成 OKhttp的 ResponseBody类型,而且接口里面默认接受的是 RequestBody类型,这个上文已经讲过。
Retrofit支持配置其他的转换器,来支持其他的类型,官网提供了如下6个可动态配置的libraries,需要哪个你就在Gradle里面配置进来。
- Gson: com.squareup.retrofit2:converter-gson
- Jackson: com.squareup.retrofit2:converter-jackson
- Moshi: com.squareup.retrofit2:converter-moshi
- Protobuf: com.squareup.retrofit2:converter-protobuf
- Wire: com.squareup.retrofit2:converter-wire
- Simple XML: com.squareup.retrofit2:converter-simplexml
- Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
下面是官网的例子,展示了如何使用其他的转换器,这个只需要在创建Retrofit对象的时候动态传入转换器就可以了。下面例子使用了Gson作为反序列化工具。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
如果官网提供的转换器无法满足你,你可以自己继承 Converter.Factory类,扩展你需要的功能
四、使用Retrofit
1. GRADLE配置
compile 'com.squareup.retrofit2:retrofit:2.1.0'
注意:Retrofit仅支持 Java 7 及 Android 2.3 以上版本。
2. PROGUARD配置
如果你的项目使用了混淆,请将如下代码添加到proguards-rules 文件夹当中。
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
网友评论