Retrofit 2 使用指南

概述

Retrofit 是 Squareup 公司开源的网络请求框架,它其实是对 OkHttp 的一层封装,使用面向接口的方式进行网络请求,利用动态生成的代理类封装了网络接口请求的底层,并且提供了对 RxJava 的支持。
写这篇文章的时候,Retrofit 已经发布 2.3.0 了,本文就以此版本来介绍。
GitHub 地址

基本用法

添加依赖:

      
      
1
2
3
      
      
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

注意 compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' 是添加了对RxJava2的支持,一定要注意RxJava的版本对应问题,否则会报错:

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
      
      
Caused by: java.lang.IllegalArgumentException: Unable to create call adapter for io.reactivex.Observable<com.example.heqiang.testsomething.testretrofit.RequestManager$TestBean>
for method RequestService.getDataRx
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:752)
at retrofit2.ServiceMethod$Builder.createCallAdapter(ServiceMethod.java:237)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:162)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:170)
at retrofit2.Retrofit$1.invoke(Retrofit.java:147)
at java.lang.reflect.Proxy.invoke(Proxy.java:393)
at $Proxy0.getDataRx(Unknown Source)
at com.example.heqiang.testsomething.testretrofit.RequestManager.getDataRx(RequestManager.java:68)
at com.example.heqiang.testsomething.rxjava.RxJavaActivity.testRetrofitRx(RxJavaActivity.java:105)
... 11 more
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for io.reactivex.Observable<com.example.heqiang.testsomething.testretrofit.RequestManager$TestBean>.
Tried:
* retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
* retrofit2.ExecutorCallAdapterFactory
at retrofit2.Retrofit.nextCallAdapter(Retrofit.java:241)
at retrofit2.Retrofit.callAdapter(Retrofit.java:205)
at retrofit2.ServiceMethod$Builder.createCallAdapter(ServiceMethod.java:235)

还有个库是 com.squareup.retrofit2:adapter-rxjava,这个是仅支持RxJava1,如果想使用 RxJava2,就要用上面的依赖。
如果需要使用 Gson 作为转换器,就需要依赖 com.squareup.retrofit2:converter-gson,如果不想使用,可以自定义,比如 FastJson 等。

先上代码:

CallBack.java

      
      
1
2
3
4
      
      
public interface CallBack<T> {
void onSuccess(T t);
void onFail(Exception e);
}

RequestService.java

      
      
1
2
3
4
5
6
7
      
      
public interface {
( "hq/urls")
Call<RequestManager.TestBean> getData();
( "hq/urls")
Observable<RequestManager.TestBean> getDataRx();
}

RequestManager.java

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
      
      
public class RequestManager {
private RequestService mRequestService;
private static volatile RequestManager sInstance;
private RequestManager(Context context){
Cache cache = new Cache( new File(context.getExternalCacheDir(), "test"), 100* 1024* 1024);
Log.e( "Test", "cache dir = " + context.getExternalCacheDir());
OkHttpClient client = new OkHttpClient.Builder()
.retryOnConnectionFailure( true)
.connectTimeout( 20, TimeUnit.SECONDS)
.cache(cache)
.build();
Retrofit retrofit = new Retrofit.Builder()
//这里如果不指定client,那么会生成一个默认的OkHttpClient
.client(client)
.baseUrl( "http://*.*.*.*/")
.addConverterFactory(GsonConverterFactory.create())
//加入对RxJava2的支持
//.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
mRequestService = retrofit.create(RequestService.class);
}
public static RequestManager getInstance(){
if(sInstance == null){
synchronized (RequestManager.class){
if(sInstance == null){
sInstance = new RequestManager();
}
}
}
return sInstance;
}
public void getData(){
Call<TestBean> call = mRequestService.getData();
// 异步请求
call.enqueue( new Callback<TestBean>() {
@Override
public void onResponse(Call<TestBean> call, Response<TestBean> response) {
Log.e( "Test", "onResponse = "+response.body().toString());
}
@Override
public void onFailure(Call<TestBean> call, Throwable t) {
}
});
// 同步请求
try {
Response<TestBean> response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
}
public static class TestBean{
public int code;
public String message;
public String redirect;
public ArrayList<String> value;
@Override
public String toString() {
return "code = "+code+ ", message = "+message+ ",redirect = "+ redirect+ ", value="+value.toString();
}
}
}

结合RxJava和RxAndroid

在上面的代码中去掉 addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 的注释,再加上定义的 Observable<RequestManager.TestBean> getDataRx() 方法,就添加了对 RxJava2 的支持。
如果需要使用 RxAndroid 还要在build.gradle中添加依赖:

      
      
1
      
      
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
      
      
public void getDataRx(final CallBack<TestBean> callBack){
mRequestService.getDataRx().subscribeOn(Schedulers.io())
// 依赖RxAndroid
.observeOn(AndroidSchedulers.mainThread())
.subscribe( new Observer<TestBean>() {
@Override
public void onError(Throwable e) {
Log.e( "Test", "onError");
callBack.onFail( new Exception(e));
}
@Override
public void onComplete() {
}
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(TestBean testBean) {
Log.e( "Test", "onNext = "+testBean.toString());
callBack.onSuccess(testBean);
}
});

CallAdapter

CallAdapter 其实就是对 Call 的转换,上面的对 RxJava 支持时用到的 RxJava2CallAdapterFactory 其实就是 CallAdapter.Factory 的子类,当然我们也可以自定义实现一个 CallAdapter

Converter

在默认情况下 Retrofit 只支持将 HTTP 的响应体转换换为 ResponseBody,那么接口的返回值都是 Call<ResponseBody>,如果我们需要把 ResponseBody 转换成我们需要的类型就需要 Converter
Converter 就是对数据的转换,代码中 addConverterFactory(GsonConverterFactory.create()) 就是指定了 Gson 将 ResponseBody转换我们想要的类型。
显然我们也可以自定义一个 Converter,比如使用 FastJson 等。

注解的使用

请求方法

  • GET
  • POST
  • PUT
  • DELETE
  • PATCH
  • HEAD
  • OPTIONS
  • HTTP

前面 6 种都是HTTP协议请求方式,使用方法和前面例子中的类似,都接受一个字符串来和 BaseUrl 组成请求Url。
HTTP 方式是对上面 6 中的扩展,用法:

      
      
1
2
      
      
@HTTP(method = "GET", path = "blog", hasBody = false)
Call<ResponseBody> getBlog();

请求参数

  • Path
  • Query
  • QueryMap

上面三种都是一个完整Url的组成部分,Path 用在 Url 的 path 部分,Query 和 QueryMap 用在参数部分,也就是Url中的 ? 后面的部分。QueryMap 相当于多个 Query。

      
      
1
2
3
      
      
( "day/{year}/{month}/{day}")
Observable<DailyDataResponse> getDailyData(
@Path( "year") int year,@ Path ("month") int month,@ Path ("day") int day);
      
      
1
2
3
      
      
( "day")
Call<Response> getDailyData(
@Query( "year") int year,@ Query ("month") int month,@ Query ("day") int day);
      
      
1
2
3
      
      
( "day")
Call<Response> getDailyData(
@QueryMap Map<String, Integer> map);
  • Field :POST请求,提交单个数据
  • FieldMap:POST请求,和@Filed作用一致,用于不确定表单参数
  • Body:POST请求,以对象的形式提交,多用于post请求发送非表单数据,比如想要以post方式传递json格式数据
      
      
1
2
3
4
      
      
@FormUrlEncoded
@POST( "add2gank")
Observable<AddToGankResponse> add2Gank(@Field("url") String url, @Field("desc") String desc, @Field("who") String who,
@ Field ("type") String type,@ Field ("debug") boolean debug);
      
      
1
2
      
      
@POST( "add2gank")
Call<Response> add2Gank(@Body ExtrasBean bean);
      
      
1
2
3
      
      
@FormUrlEncoded
@POST( "add2gank")
void add2Gank(@FieldMap Map<String, String> map)

可以看到这里多了一个 @FormUrlEncoded 注解,如果去掉 @FromUrlEncoded 在 post 请求中使用 @Field@FieldMap,那么程序会抛出 java.lang.IllegalArgumentException: @Field parameters can only be used with form encoding. (parameter #1) 的错误异常。
如果将 @FromUrlEncoded 添加在 @GET 上面呢,同样的也会抛出 java.lang.IllegalArgumentException:FormUrlEncoded can only be specified on HTTP methods with request body (e.g., @POST) 的错误异常。
如果是使用 @Body,也是不用加 @FormUrlEncoded 注解的。

  • Url:实现动态Url

前面的使用都是基于BaseUrl的,如果我们想请求不同Url时只能重新生成一个 Retrofit 实例,实际上我们还可以通过 @Url 来操作。

      
      
1
2
      
      
@GET
public Call<ResponseBody> getImage(@Url String url);

如果参数指定的 url 是一个以 http 开头的 url,那么就完全使用这个url,和前面指定的 BaseUrl 完全没有联系,如果 url 指定的只有类似 /id/name 的path,而没有指定 scheme 和 host,那么它就会用 BaseUrl 的 scheme 和 host。
这里注意 :只是用 BaseUrl 的 scheme 和 host,如果 BaseUrl 是 http://www.test.com/v/ ,那么还是会把 path 中的 v 去掉,组成 http://www.test.com/id/name

  • Header:用于在方法参数里动态添加请求头:
      
      
1
      
      
Call<ResultBean> postSayHi(@Header("city") String city);
  • Part
  • PartMap

这两个用于上传文件,与 @MultiPart 注解结合使用

      
      
1
2
3
      
      
@Multipart
@POST("test/upload")
Call<ResultBean> upload(@Part("file"; filename="launcher_icon.png") RequestBody file);

方法注解

  • FormUrlEncoded:上面已经介绍过了。
  • Headers:用于在方法添加请求头
      
      
1
2
3
      
      
@POST("test/sayHi")
@Headers("Accept-Encoding: application/json")
Call<ResultBean> postSayHi(@Body UserBean userBean, @Header("city") String city);
  • Streaming:如果您正在下载一个大文件,Retrofit2将尝试将整个文件移动到内存中。为了避免这种,我们必须向请求声明中添加一个特殊的注解
      
      
1
2
3
      
      
@Streaming
@GET
Call<ResponseBody> downloadFileByDynamicUrl(@Url String fileUrl);

原文:大专栏  Retrofit 2 使用指南


猜你喜欢

转载自www.cnblogs.com/petewell/p/11601756.html