1.Retrofit干什么的?
Retrofit让你便捷地封装出一个类来给其它地方调用和服务器进行HTTP API调用。
比如,一般来说,不用retrofit的时候,你需要填写http参数,然后get数据下来,然后解析,然后。。。。
用了retrofit之后,你只需a.xxget("参数值")拿到一个对象,就可访问服务器返回的数据了。
retrofit一般都是结合okhttp使用。
2.定义服务接口类
要想做到上面说的“a.xxget”就能简单调用HTTP服务器上的API,需要定义一个interface类,然后使用retrofit对这个类进行实现。
例如下面的interface类:
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); }
然后通过retrofit提供的功能来配置和实现这个接口:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class);
这样,如果你调用service.listRepos("xiaoli")就等效于访问了“https://api.github.com/users/xiaoli/repos”,并拿到这个地方返回的数据。像下面这样:
Call<List<Repo>> repos = service.listRepos("xiaoli");
3.注解编写
retrofit一大特点就是通过注解来定制调用服务器API时候HTTP请求的一些参数配置。所以需要了解如何retrofit支持的注解。
retrofi一共有5个注解:GET,POST,PUT,DELETE,HEAD。
每个API都要写上相关的注解,说明API是怎么调用的。
例如以下的GET注解,表示“listRepos”函数使用GET的方法访问HTTP的网址:
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); }
接下来详细介绍一下注解使用规则。
4.URL封装
“@Path”:地址中关联变量
注解中的url地址,可以和变量关联,用大括号(“{ }”)包括,而相应地,在函数参数中用@Path指明变量就可以。
例如下面的变量“id”:
@GET("group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId);
“@Query”:关联单个查询参数变量
API中如有“?”后面的那些参数,可以用“@Query”来关联变量。
例如有这样一个API请求URL(两个查询参数:access_token和openid):
https://login.xx.cn/mobile/login?access_token=12345&openid=56789
相应retrofit的规则写法如下:
@GET("/mobile/login") void getMyMessage(@Query("access_token") String access_token, @Query("openid") String openId);
"@QueryMap" : 关联多个查询参数变量
API中如果有很多查询参数,每个都写一个“@Query”明显太麻烦,所以retrofit又提供了“@QueryMap ”可以一次指定多个参数变量。
例如上面的接口又可以这样写:
@GET("/mobile/login") void getMyMessage(@QueryMap HashMap<String,String> queryparams);
使用的时候:
HashMap<String,String> params = new HashMap();
params.put("access_token",token);
params.put("openid",openid);
serviceAPI.getMyMessage(params);
注意:“@QueryMap”使用在POST方法,参数会写在url中,服务器编写要注意接收参数而不是body。
5.Header封装
“@Headers”:指定Header域数据
例如:
@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与数据动态关联
可以在接口参数中使用“@Header”动态关联变量,
例如下面的代码,关联了“Authorization”域的值由变量authorization提供:
@GET("user") Call<User> getUser(@Header("Authorization") String authorization)
注意:如果每个请求都想添加一些特定头域数据,请使用okhttp的拦截器。
okhttp拦截器的例子:
OkHttpClient client = new OkHttpClient();
client.networkInterceptors().add(new Interceptor() {
@Override
public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
com.squareup.okhttp.Response response = chain.proceed(chain.request());
tokenRequest = response.newBuilder()
.header("token", "1234567")
.build();
return chain.proceed(tokenRequest);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
...
.client(client)
.build();
6.请求数据体封装设置
“@FormUrlEncoded ”: 变量提供表单式数据
会以application/x-www-form-urlencoded类型作为body,参考例子:
@FormUrlEncoded @POST("user/edit") Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
注意使用了“@Field”来定义了key-value的键值对数据。
"@Multipart " : 关联变量实现multipart数据提供
使用“@Part”来关联变量动态对part提供数据。
参考例子:
@Multipart @PUT("user/photo") Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
“@Body”: 实现请求的数据体关联变量
参考下面的例子:
@POST("/mobile/login") void getMyMessage(@Body HashMap<String,String> reqbodydata);
另外一种,使用java类实体变量的例子:
@POST("/mobile/login") void getMyMessage(@Body User reqbodydata);
7.同步和异步特性
可以通过Call方式实现同步或者异步调用,每个Call实例只能调用一次。需要再调用,则要clone一个新的。
看例子。
定义:
import retrofit.Call;
/* Retrofit 2.0 */
public interface APIService {
@POST("/list")
Call<Repo> loadRepo();
}
同步调用:
// Synchronous Call in Retrofit 2.0
Call<Repo> call = service.loadRepo();
Repo repo = call.execute();
异步调用:
// Synchronous Call in Retrofit 2.0
Call<Repo> call = service.loadRepo();
call.enqueue(new Callback<Repo>() {
@Override
public void onResponse(Response<Repo> response) {
// Get result Repo from response.body()
}
@Override
public void onFailure(Throwable t) {
}
});
注意,Callback被调用的时候,如果是android平台,是在主线程,而如果是“JVM”中,则和HTTP请求同一个线程。可以取消正在进行的请求:call.cancel() 。
8.结束
retrofit是个方便我们调用服务器API的一个工具,如果很多API接口,可以考虑使用,如果只是一两个,没必要搞那么复杂。