前言
最近有個想法——就是把 Android 主流開源框架進(jìn)行深入分析换怖,然后寫成一系列文章,包括該框架的詳細(xì)使用與源碼解析蟀瞧。目的是通過鑒賞大神的源碼來了解框架底層的原理沉颂,也就是做到不僅要知其然,還要知其所以然悦污。
這里我說下自己閱讀源碼的經(jīng)驗铸屉,我一般都是按照平時使用某個框架或者某個系統(tǒng)源碼的使用流程入手的,首先要知道怎么使用切端,然后再去深究每一步底層做了什么彻坛,用了哪些好的設(shè)計模式,為什么要這么設(shè)計。
系列文章:
- Android 主流開源框架(一)OkHttp 鋪墊-HttpClient 與 HttpURLConnection 使用詳解
- Android 主流開源框架(二)OkHttp 使用詳解
- Android 主流開源框架(三)OkHttp 源碼解析
- Android 主流開源框架(四)Retrofit 使用詳解
- Android 主流開源框架(五)Retrofit 源碼解析
- Android 主流開源框架(六)Glide 的執(zhí)行流程源碼解析
- 更多框架持續(xù)更新中...
更多干貨請關(guān)注 AndroidNotes
一昌屉、Retrofit 介紹
前面的文章已經(jīng)介紹了 OkHttp 的使用 與 OkHttp 源碼分析钙蒙,不了解的強烈建議先看看這 2 篇文章。這篇介紹的是 Retrofit间驮,它也是 Square 公司開源的網(wǎng)絡(luò)框架躬厌,它的底層就是基于 OkHttp 實現(xiàn)的,不過它比 OkHttp 使用更方便竞帽,也更適合進(jìn)行 RESTful API 格式的請求扛施。
二、Retrofit 的使用
2.1 使用前準(zhǔn)備
(1)加入網(wǎng)絡(luò)權(quán)限 在 AndroidManifest.xml 文件中加入如下:
<uses-permission android:name="android.permission.INTERNET"/>
(2)添加 Retrofit 庫的依賴
因為需要將服務(wù)器返回的 ResponseBody 轉(zhuǎn)換成實體類屹篓,所以需要添加 Gson 庫的依賴作為數(shù)據(jù)解析器疙渣。
最終在當(dāng)前使用的 module 下的 build.gradle 中加入如下依賴:
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
// Gson
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
2.2 簡單的 GET 請求
這里使用 postman 提供的 GET 接口進(jìn)行演示。(Postman Echo)
(1)創(chuàng)建一個實體類堆巧,用于接收服務(wù)器返回的數(shù)據(jù):
public class PostmanGetBean {
private String url;
// 其余字段省略昌阿,具體看 demo。
}
(2)創(chuàng)建一個接口恳邀,用于定義網(wǎng)絡(luò)請求:
public interface PostmanService {
@GET("get")
Call<PostmanGetBean> testGet();
}
可以看到懦冰,這里有一個 testGet() 方法,方法上面的注解 @GET 表示 GET 請求谣沸,注解里面的 “get” 會與后面的 baseUrl 拼接成完整的路徑刷钢。例如 baseUrl 為 https://postman-echo.com/
,則完整的路徑為 https://postman-echo.com/get
乳附。這里建議 baseUrl 以 /(斜線)結(jié)尾内地,注解中的 path 統(tǒng)一不要以 /(斜線)開頭,因為這種方式看起來比較直觀赋除。
(3)創(chuàng)建 Retrofit 的實例:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://postman-echo.com/")// baseUrl
.addConverterFactory(GsonConverterFactory.create())// 解析json數(shù)據(jù)
.build();
(4)創(chuàng)建網(wǎng)絡(luò)請求接口的實例阱缓,并調(diào)用接口中的方法獲取 Call 對象:
PostmanService service = retrofit.create(PostmanService.class);
Call<PostmanGetBean> call = service.testGet();
(5)進(jìn)行網(wǎng)絡(luò)請求
call.enqueue(new Callback<PostmanGetBean>() {
@Override
public void onResponse(Call<PostmanGetBean> call, Response<PostmanGetBean> response) {
System.out.println(response.body().getUrl());
}
@Override
public void onFailure(Call<PostmanGetBean> call, Throwable t) {
}
});
打印結(jié)果:
https://postman-echo.com/get
示例源碼:RetrofitActivity-testGetRequest
三、Retrofit 注解說明
Retrofit 中使用了大量的注解举农,這里將這些注解分成 3 類荆针。
3.1 第一類:網(wǎng)絡(luò)請求方法
分別是 @GET、@POST颁糟、@PUT航背、@DELETE、@PATH棱貌、@HEAD玖媚、@OPTIONS 和 @HTTP,前 7 個分別對應(yīng) HTTP 中的網(wǎng)絡(luò)請求方法婚脱,都接收一個字符串與 baseUrl 組成完整的 URL今魔,也可以不指定勺像,通過 @HTTP 注解設(shè)置。最后一個 @HTTP 注解可以用來替換前面 7 個注解错森,以及其他擴(kuò)展功能咏删。
這里主要講下 @HTTP 注解,其他注解與 @GET 注解類似问词。
@HTTP 注解示例:
@HTTP 注解有 3 個屬性:method督函、path 與 hasBody,上面說了這個注解可以用來替換前面 7 個注解激挪,所以就替換一下前面講到 GET 請求中的 @GET 注解吧辰狡。
這里只需要修改接口即可,其他不變:
public interface PostmanService {
@HTTP(method = "GET", path = "get", hasBody = false)
Call<PostmanGetBean> testHTTP();
}
運行結(jié)果:
與 @GET 注解示例一樣垄分。
示例源碼:RetrofitActivity-testHTTP
3.2 第二類:標(biāo)記
3.2.1 @FormUrlEncoded 注解
簡介: 表示請求體是一個 Form 表單宛篇。
示例:
這里使用 postman 提供的 POST 接口進(jìn)行演示。
單個鍵值對傳:
(1)創(chuàng)建實體類:
public class PostmanPostBean {
// 字段與重寫 toString() 方法省略薄湿,具體看 demo
}
(2)創(chuàng)建接口:
public interface PostmanService {
@POST("post")
@FormUrlEncoded
Call<PostmanPostBean> testFormUrlEncoded1(@Field("username") String name, @Field("password") String password);
}
可以看到叫倍,這里使用了 @Field 注解,它屬于第三類注解豺瘤,用來向 Post 表單傳入鍵值對吆倦,其中 username 表示鍵,name 表示值坐求。
(3)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://postman-echo.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
PostmanService service = retrofit.create(PostmanService.class);
Call<PostmanPostBean> call = service.testFormUrlEncoded1("wildma", "123456");
call.enqueue(new Callback<PostmanPostBean>() {
@Override
public void onResponse(Call<PostmanPostBean> call, Response<PostmanPostBean> response) {
System.out.println(response.body().getForm().toString());
}
@Override
public void onFailure(Call<PostmanPostBean> call, Throwable t) {
}
});
運行結(jié)果:
FormEntity{username='wildma', password='123456'}
示例源碼:RetrofitActivity-testFormUrlEncoded1
傳入一個 Map 集合:
向 Post 表單傳入鍵值對除了上面一個個傳蚕泽,還可以使用注解 @FieldMap 傳一個 Map 集合,如下:
(1)創(chuàng)建接口:
public interface PostmanService {
@POST("post")
@FormUrlEncoded
Call<PostmanPostBean> testFormUrlEncoded2(@FieldMap Map<String, Object> map);
}
(3)發(fā)起請求:
// 省略創(chuàng)建 Retrofit 的實例代碼
Map<String, Object> map = new HashMap<>();
map.put("username", "wildma");
map.put("password", "123456");
Call<PostmanPostBean> call = service.testFormUrlEncoded2(map);
// 省略網(wǎng)絡(luò)請求代碼
示例源碼:RetrofitActivity-testFormUrlEncoded2
3.2.2 @Multipart 注解
簡介: 表示請求體是一個支持文件上傳的 Form 表單桥嗤。
示例:
這里使用 YESAPI 提供的圖片上傳接口進(jìn)行演示须妻。
單文件上傳:
(1)創(chuàng)建實體類:
public class UploadImgBean {
// 字段與重寫 toString() 方法省略,具體看 demo
}
(2)創(chuàng)建接口:
public interface FileUploadService {
@POST("?service=App.CDN.UploadImg")
@Multipart
Call<UploadImgBean> testFileUpload1(@Part MultipartBody.Part file, @Part("app_key") RequestBody appKey);
}
可以看到泛领,這里使用了 @Part 注解荒吏,它屬于第三類注解,用于表單字段渊鞋,適用于有文件上傳的情況绰更。這里使用了@Part 的兩種類型,MultipartBody.Part 表示上傳一個文件篓像,RequestBody 表示傳一個鍵值對动知,其中 app_key 表示鍵皿伺,appKey 表示值员辩。
(3)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://hn216.api.yesapi.cn/")
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestBody appKey = RequestBody.create(null, "替換成你在 YESAPI 上獲取的 appKey");
// test.png 為 SD 卡跟目錄下的文件,需要提前放好
File file = new File(Environment.getExternalStorageDirectory(), "test.png");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
// 構(gòu)建 MultipartBody.Part鸵鸥,其中 file 為服務(wù)器約定好的 key奠滑,test.png 為文件名稱
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.png", requestBody);
FileUploadService service = retrofit.create(FileUploadService.class);
Call<UploadImgBean> call = service.testFileUpload1(filePart, appKey);
call.enqueue(new Callback<UploadImgBean>() {
@Override
public void onResponse(Call<UploadImgBean> call, Response<UploadImgBean> response) {
System.out.println(response.body().toString());
}
@Override
public void onFailure(Call<UploadImgBean> call, Throwable t) {
}
});
運行結(jié)果:
UploadImgBean{ret=200, data=DataEntity{err_code=0, err_msg='', url='http://cd7.yesapi.net/xxx.png'}, msg='當(dāng)前小白接口:App.CDN.UploadImg'}
示例源碼:RetrofitActivity-testFileUpload1
多文件上傳:
如果想上傳多個文件丹皱,則可以使用注解 @PartMap 傳一個鍵值對為 <String, RequestBody> 的 Map 集合,如下:
(1)創(chuàng)建接口:
public interface FileUploadService {
@POST("?service=App.CDN.UploadImg")
@Multipart
Call<UploadImgBean> testFileUpload2(@PartMap Map<String, RequestBody> map);
}
(1)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://hn216.api.yesapi.cn/")
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestBody appKey = RequestBody.create(null, "替換成你在 YESAPI 上獲取的 appKey");
// test.png 為 SD 卡跟目錄下的文件宋税,需要提前放好
File file = new File(Environment.getExternalStorageDirectory(), "test.png");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
Map<String, RequestBody> requestBodyMap = new HashMap<>();
requestBodyMap.put("app_key", appKey);
// 加入一個文件摊崭,其中 file 為服務(wù)器約定好的 key,test.png 為文件名稱
requestBodyMap.put("file\"; filename=\"test.png", requestBody);
// 有更多文件杰赛,則繼續(xù) put()...
FileUploadService service = retrofit.create(FileUploadService.class);
Call<UploadImgBean> call = service.testFileUpload2(requestBodyMap);
call.enqueue(new Callback<UploadImgBean>() {
@Override
public void onResponse(Call<UploadImgBean> call, Response<UploadImgBean> response) {
System.out.println(response.body().toString());
}
@Override
public void onFailure(Call<UploadImgBean> call, Throwable t) {
}
});
示例源碼:RetrofitActivity-testFileUpload2
3.2.3 @Streaming 注解
簡介: 表示響應(yīng)體的數(shù)據(jù)用流的形式返回呢簸,如果沒有使用該注解,默認(rèn)會把數(shù)據(jù)全部載入內(nèi)存乏屯,之后獲取數(shù)據(jù)就從內(nèi)存中讀取根时,所以該注解一般用在返回數(shù)據(jù)比較大的時候,例如下載大文件辰晕。
示例:
這里使用下載我的博客頭像( https://wildma.github.io/medias/avatars/avatar.jpg ) 進(jìn)行演示蛤迎。
(1)下載文件不需要創(chuàng)建一個實體類,直接用 ResponseBody 來接收服務(wù)器返回的數(shù)據(jù)含友。(后面的示例為了方便演示替裆,也不再解析成實體類,直接用 ResponseBody 來接收服務(wù)器返回的原始數(shù)據(jù))
(2)創(chuàng)建接口:
public interface FileDownloadService {
@Streaming
@GET("medias/avatars/avatar.jpg")
Call<ResponseBody> testFileDownload();
}
這里使用了 @Streaming 注解用來表示響應(yīng)體的數(shù)據(jù)用流的形式返回窘问。
(3)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://wildma.github.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
FileDownloadService service = retrofit.create(FileDownloadService.class);
Call<ResponseBody> call = service.testFileDownload();
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
InputStream is = response.body().byteStream();
// 保存文件...
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
示例源碼:RetrofitActivity-testFileDownload
3.3 第三類:網(wǎng)絡(luò)請求參數(shù)
3.3.1 @Header辆童、@Headers 與 @HeaderMap 注解
簡介: @Header 與 @HeaderMap 用于添加不固定值的請求頭,@Headers 用于添加固定值的請求頭惠赫。@Header 與 @HeaderMap 是作為請求方法的參數(shù)傳入胸遇,@Headers 則直接添加到請求方法上。
示例:
// @Header
@GET("headers")
Call<ResponseBody> testHeader(@Header("token") String token);
// @Headers
@Headers("token: 123")
@GET("headers")
Call<ResponseBody> testHeaders();
// @Headers 多個請求頭
@Headers({"token: 123", "sign: 456"})
@GET("headers")
Call<ResponseBody> testHeaders2();
// @HeaderMap
@GET("headers")
Call<ResponseBody> testHeaderMap(@HeaderMap Map<String, String> map);
示例源碼:RetrofitActivity-testHeader()汉形、testHeaders()纸镊、testHeaders2()
3.3.2 @Body 注解
簡介: @Body 用于非表單請求體。很多時候后臺要求前端傳一個 json 字符串的請求體概疆,這時候我們可以使用 @Body 注解來輕松實現(xiàn)逗威,因為該注解可以直接傳一個實體類,發(fā)起請求的過程中會把該實體類轉(zhuǎn)換成 json 字符串的請求體傳給后臺岔冀。
示例:
(1)創(chuàng)建接口:
public interface PostmanService {
@POST("post")
Call<ResponseBody> testBody(@Body TestBodyBean testBodyBean);
}
(2)發(fā)起請求:
// 省略創(chuàng)建 Retrofit 的實例代碼
TestBodyBean bean = new TestBodyBean();
bean.setUsername("wildma");
bean.setPassword("123456");
PostmanService service = retrofit.create(PostmanService.class);
Call<ResponseBody> call = service.testBody(bean);
// 省略網(wǎng)絡(luò)請求代碼
示例源碼:RetrofitActivity-testBody()
3.3.3 @Field 與 @FieldMap 注解
簡介: 用于向 Post 表單傳入鍵值對凯旭。
示例:
具體使用前面講 @FormUrlEncoded 注解的時候已經(jīng)講過了。
示例源碼:RetrofitActivity-testFormUrlEncoded1()使套、testFormUrlEncoded2()
3.3.4 @Part 與 @PartMap 注解
簡介: 用于表單字段罐呼,適用于有文件上傳的情況。
示例:
具體使用前面講 @Multipart 注解的時候已經(jīng)講過了侦高。
示例源碼:RetrofitActivity-testFileUpload1()嫉柴、testFileUpload2()
3.3.5 @Query 與 @QueryMap 注解
簡介: 用于表單字段,功能與 @Field奉呛、@FiledMap 一樣计螺,區(qū)別在于 @Query夯尽、@QueryMap 的數(shù)據(jù)體現(xiàn)在 URL 上,而 @Field登馒、@FiledMap 的數(shù)據(jù)體現(xiàn)在請求體上瓮顽,但生成的數(shù)據(jù)是一樣的畏吓。
示例:
(1)創(chuàng)建接口:
public interface PostmanService {
@GET("get")
Call<ResponseBody> testQuery(@Query("username") String username);
}
(2)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://postman-echo.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
PostmanService service = retrofit.create(PostmanService.class);
Call<ResponseBody> call = service.testQuery("wildma");
// 省略網(wǎng)絡(luò)請求代碼
上面的 baseUrl 為 https://postman-echo.com/
,@GET 注解中的部分 URL 為 “get”,最終完整 URL 如果沒用 @Query 注解應(yīng)該是 https://postman-echo.com/get
谍倦,用了注解就變成 https://postman-echo.com/get?username=wildma
了弟疆。
@QueryMap 注解則對應(yīng) Map 集合钧排,接口如下:
public interface PostmanService {
@GET("get")
Call<ResponseBody> testQueryMap(@QueryMap Map<String, String> params);
}
發(fā)起請求的代碼就不貼出來了忆植,傳一個對應(yīng)的 Map 集合進(jìn)來即可。
示例源碼:RetrofitActivity-testQuery()法褥、testQueryMap()
3.3.6 @QueryName 注解
簡介: 用于沒有值的查詢參數(shù)茫叭,該注解實際項目中很少用到,功能與 @Query半等、@QueryMap 類似揍愁,參數(shù)都拼接在 URL 上,但是 @Query杀饵、@QueryMap 在 URL 上是以鍵值對拼接的莽囤,而 @QueryName 只是拼接鍵,沒有值切距。
示例:
(1)創(chuàng)建接口:
public interface PostmanService {
@GET("get")
Call<ResponseBody> testQueryName(@QueryName String... filters);
}
注解后面可跟 String filter朽缎,也可跟 String... filters,其中后者是可變長參數(shù)谜悟,可以傳多個參數(shù)也可不傳參數(shù)话肖。
(2)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://postman-echo.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
PostmanService service = retrofit.create(PostmanService.class);
Call<ResponseBody> call = service.testQueryName("wildma","tom");
// 省略網(wǎng)絡(luò)請求代碼
上面最終拼接的 URL 為 https://postman-echo.com/get?wildma&tom
。
示例源碼:RetrofitActivity-testQueryName()
3.3.7 @Path 注解
簡介: @Path 用于設(shè)置 URL 地址的缺省值葡幸。
示例:
這里使用官方提供的 API最筒,即獲取指定用戶的倉庫列表進(jìn)行演示。
(1)創(chuàng)建接口:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<RepoBean>> listRepos(@Path("user") String user);
}
(2)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<ResponseBody> call = service.testPath("wildma");
// 省略網(wǎng)絡(luò)請求代碼
可以看到蔚叨,@GET 注解里面的 “users/{user}/repos” 中有一個 “{user}”床蜘,這個就是 URL 地址的缺省值, listRepos() 方法中的 @Path("user") String user 表示傳入的 urse 就是用來替換上面的 {user} 的蔑水。所以最終完整的 URL 為 https://api.github.com/users/wildma/repos
邢锯。
示例源碼:RetrofitActivity-testPath()
3.3.8 @Url 注解
簡介: @Url 用于動態(tài)設(shè)置一個完整的 URL。
示例:
(1)創(chuàng)建接口:
public interface PostmanService {
@GET()
Call<ResponseBody> testUrl(@Url String url);
}
(2)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
PostmanService service = retrofit.create(PostmanService.class);
Call<ResponseBody> call = service.testUrl("https://postman-echo.com/get");
// 省略網(wǎng)絡(luò)請求代碼
可以看到搀别,baseUrl() 與 testUrl() 都設(shè)置了一個 URL丹擎,但由于 @Url 注解標(biāo)識的 URL 是動態(tài)設(shè)置的,所以最終以 testUrl() 中設(shè)置的為準(zhǔn)领曼,也就是最終使用的是 https://postman-echo.com/get
鸥鹉。
示例源碼:RetrofitActivity-testUrl()
四蛮穿、設(shè)置自定義的 OkHttpClient
在創(chuàng)建 Retrofit 的實例的時候可以通過 client() 方法設(shè)置自定義的 OkHttpClient庶骄,自定義 OkHttpClient 可以設(shè)置統(tǒng)一的 header毁渗,添加 log 攔截器、Cookie 等单刁。這里就講下怎么設(shè)置統(tǒng)一的 header 吧灸异!
(1)創(chuàng)建 OkHttpClient 的時候通過添加攔截器,然后在攔截器的 intercept() 方法中設(shè)置統(tǒng)一的 header:
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request request = originalRequest.newBuilder()
.header("token", "123")
.header("sign", "456")
.build();
return chain.proceed(request);
}
}).build();
(2)通過 client() 方法設(shè)置自定義的 OkHttpClient:
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)// 設(shè)置自定義的 OkHttpClient
.baseUrl("https://postman-echo.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
示例源碼:RetrofitActivity-testCustomOkHttpClient
五羔飞、關(guān)于 Converter
Retrofit 默認(rèn)用 ResponseBody 來接收服務(wù)器返回的數(shù)據(jù)肺樟,如果想要轉(zhuǎn)換成對應(yīng)的實體類,那么在創(chuàng)建 Retrofit 的實例的時候可以通過 addConverterFactory() 方法設(shè)置一個數(shù)據(jù)解析器逻淌,數(shù)據(jù)解析器有多種選擇么伯,Retrofit 文檔中就提供了很多種:
- 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
除了文檔提供的這幾種,其實還有一種常用的:
fastjson:'org.ligboy.retrofit2:converter-fastjson-android
這里使用 Gson 進(jìn)行演示卡儒。
(1)創(chuàng)建接口:
public interface PostmanService {
@GET("get")
Call<PostmanGetBean> testGet();
}
這里直接用實體類 PostmanGetBean 替換 ResponseBody田柔。
(2)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://postman-echo.com/")
.addConverterFactory(GsonConverterFactory.create())// 添加 Gson 解析器
.build();
// 省略網(wǎng)絡(luò)請求代碼
這里添加了 Gson 作為數(shù)據(jù)解析器。
六骨望、關(guān)于 CallAdapter
前面創(chuàng)建接口的時候硬爆,發(fā)現(xiàn)接口中的方法返回類型都是 Call,如果想要返回其他類型擎鸠,那么在創(chuàng)建 Retrofit 的實例的時候可以通過 addCallAdapterFactory() 方法設(shè)置一個 CallAdapter缀磕,Retrofit 提供了如下 CallAdapter:
- guava:com.squareup.retrofit2:adapter-guava
- Java8:com.squareup.retrofit2:adapter-java8:2.0.2
- rxjava:com.squareup.retrofit2:adapter-rxjava
這里使用 RxJava 進(jìn)行演示。
(1)添加相關(guān)依賴:
// 支持 rxjava2
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
// rxjava2
compile 'io.reactivex.rxjava2:rxjava:2.2.13'
compile 'io.reactivex.rxjava2:rxandroid:2.1.1'
(2)創(chuàng)建接口:
@GET("get")
Observable<ResponseBody> testCallAdapter();
這里使用 Observable 替換 Call劣光。
(3)發(fā)起請求:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://postman-echo.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())// 設(shè)置 RxJava 作為當(dāng)前的 CallAdapter
.build();
PostmanService service = retrofit.create(PostmanService.class);
Observable<ResponseBody> observable = service.testCallAdapter();
observable.subscribeOn(Schedulers.io()) // 在 IO 線程進(jìn)行網(wǎng)絡(luò)請求
.observeOn(AndroidSchedulers.mainThread()) // 在主線程處理請求結(jié)果
.subscribe(new Observer<ResponseBody>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseBody responseBody) {
try {
System.out.println(responseBody.string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
這里設(shè)置 RxJava 作為當(dāng)前的 CallAdapter袜蚕,并且調(diào)用 Observable 的相關(guān)方法進(jìn)行網(wǎng)絡(luò)請求與請求結(jié)果的處理。
示例源碼:RetrofitActivity-testCallAdapter