本博客為作者原創(chuàng),如需轉(zhuǎn)載請(qǐng)注明原博客出處:WONDER'TWO
0X00 寫(xiě)在前面
相信做過(guò)Android網(wǎng)絡(luò)請(qǐng)求的同學(xué)都繞不開(kāi)Volley芹橡,Retrofit息裸,OkHttp這幾座大山姐刁,至于他們的前世姻緣以及孰優(yōu)孰劣,不在本博客的討論范圍禀崖。如題礁鲁,這篇博客主要介紹一個(gè)小白(其實(shí)就是我自己)的Retrofit2進(jìn)階之路盐欺,會(huì)結(jié)合一個(gè)開(kāi)發(fā)實(shí)例介紹5節(jié)內(nèi)容:
- Retrofit2 HTTP請(qǐng)求方法注解的字段說(shuō)明
-
Call<T>
響應(yīng)結(jié)果的處理問(wèn)題 - Retrofit2+RxJava實(shí)現(xiàn)開(kāi)發(fā)效率最大化
- 自定義OkHttp Interceptor實(shí)現(xiàn)日志輸出,保存和添加Cookie
- 自定義ResponseConverter仅醇,自定義HTTP請(qǐng)求注解
先來(lái)回顧一下Retrofit2
在項(xiàng)目中的完整使用流程:創(chuàng)建Bean類 --> 創(chuàng)建接口形式的http
請(qǐng)求方法 --> 通過(guò)Retrofit.builder()
創(chuàng)建接口對(duì)象并調(diào)用http
方法請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù) --> 在RxJava
的Observable
(被觀察者)中異步處理請(qǐng)求結(jié)果冗美!
那么Retrofit2 Http 請(qǐng)求方法注解有那么多字段,都代表什么含義呢析二?添加請(qǐng)求頭或者大文件上傳的請(qǐng)求方法該怎么寫(xiě)呢粉洼?這將在第二節(jié)介紹。另外甲抖,Retrofit2基本用法的網(wǎng)絡(luò)響應(yīng)結(jié)果是一個(gè)Call<T>
漆改,那么怎樣在Android中解析Call<T>
呢?將在第二節(jié)介紹准谚。第三節(jié)根據(jù)Retrofit2使用流程介紹了一個(gè)實(shí)踐項(xiàng)目是怎樣使用Retrofit2+RxJava
做網(wǎng)絡(luò)請(qǐng)求。第四節(jié)和四五節(jié)是Retrofit實(shí)現(xiàn)一些復(fù)雜需求的必殺技去扣,介紹了自定義OkHttp Interceptor實(shí)現(xiàn)日志輸出柱衔,保存和添加Cookie;自定義ResponseConverter愉棱,自定義HTTP請(qǐng)求注解等內(nèi)容唆铐。
0X01 Retrofit2 HTTP請(qǐng)求方法注解的字段說(shuō)明
從Retrofit2的官方文檔來(lái)看,Retrofit2 進(jìn)行網(wǎng)絡(luò)請(qǐng)求的URL分為兩部分:BaseURL和relativeURL奔滑。BaseURL需要以/
結(jié)尾艾岂, 一般不需要變化直接定義即可,當(dāng)然在特殊的情況下朋其,比如后一次網(wǎng)絡(luò)訪問(wèn)URL需要從前一次訪問(wèn)結(jié)果中獲取相關(guān)參數(shù)王浴,那么就需要?jiǎng)討B(tài)的操作URL脆炎,這種用法會(huì)第五節(jié)進(jìn)行介紹;relativeURL與每次請(qǐng)求的參數(shù)相關(guān)氓辣,所以每個(gè)request 方法都需要 http annotation 來(lái)提供請(qǐng)求的relativeURL秒裕,Retrofit2內(nèi)置的注解有五個(gè):GET, POST, PUT, DELETE, and HEAD.
這些注解在使用時(shí)涉及到哪些相關(guān)的字段呢?我從參考文獻(xiàn)的博客中引用了一張圖:
可以看到钞啸,有URL請(qǐng)求參數(shù)几蜻,Query
參數(shù)這些簡(jiǎn)單網(wǎng)絡(luò)請(qǐng)求參數(shù);同時(shí)還支持用@Header
添加請(qǐng)求頭体斩;POST
請(qǐng)求中常用@FormUrlEncoded
提交表單梭稚,并用@Field
定義表單域;@MultiPart
文件上傳并用@Part
定義請(qǐng)求體絮吵。來(lái)看一個(gè)具體的例子(摘自Retrofit2官方文檔):
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit2把網(wǎng)絡(luò)請(qǐng)求定義成接口的形式哨毁,如上是一個(gè)GET請(qǐng)求,@Path
表示一個(gè)占位符源武,@Path
中的變量必須與@GET
變量中{
和 }
中間的部分一致扼褪。下面是一個(gè)POST請(qǐng)求,@FormUrlEncoded
用于提交一個(gè)表單粱栖,@Field
定義了表單的name和value话浇。更多詳細(xì)的用法詳見(jiàn)Retrofit2官方文檔API Declaration ,另外Retrofit請(qǐng)求參數(shù)注解字段說(shuō)明 這篇博客介紹的比較詳細(xì)可作參考:
public interface GitHubService {
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
}
0X02 Call<T>
響應(yīng)結(jié)果的處理
細(xì)心的你有木有發(fā)現(xiàn)闹究,發(fā)現(xiàn)官方文檔中給出的請(qǐng)求方法示例幔崖,返回結(jié)果都是 Call<List<User>>
這種形式?沒(méi)錯(cuò)渣淤!這就是Retrofit2最原始的網(wǎng)絡(luò)請(qǐng)求用法赏寇,官方文檔上介紹的很簡(jiǎn)潔,可以在 call<T>
響應(yīng)對(duì)象上做異步或者同步的操作价认,每個(gè) call<T>
對(duì)象只能用一次嗅定,要想多次使用可以調(diào)用 clone()
方法來(lái)克隆出多個(gè) call
對(duì)象以供更多操作使用。因?yàn)镽etrofit2 是一個(gè)類型安全的Java和Android網(wǎng)絡(luò)請(qǐng)求庫(kù)用踩,所以以上的操作對(duì) Java 網(wǎng)絡(luò)請(qǐng)求也是適用的渠退。
針對(duì)JVM而言,網(wǎng)絡(luò)請(qǐng)求和結(jié)果處理會(huì)放在同一個(gè)線程中執(zhí)行脐彩,那么在Android中碎乃,我們?cè)鯓犹幚碚?qǐng)求結(jié)果對(duì)象 call
呢?官方文檔也給出了答案惠奸,我們都知道Android中網(wǎng)絡(luò)請(qǐng)求這類耗時(shí)操作都是放在工作線程(即worker thread)來(lái)執(zhí)行的梅誓,然后在主線程(也即 UI thread)處理網(wǎng)絡(luò)請(qǐng)求結(jié)果,自然Retrofit2也不例外,由于Retrofit2拋棄了飽受詬病的Apache HttpClient底層只依賴OkHttp3.0梗掰,網(wǎng)絡(luò)訪問(wèn)層的操作都會(huì)交由OkHttp來(lái)完成嵌言,而OkHttp不僅擁有自動(dòng)維護(hù)的socket連接池,減少握手次數(shù)愧怜,而且還擁有隊(duì)列線程池呀页,可以輕松寫(xiě)并發(fā),同時(shí)還支持socket自動(dòng)選擇最好路線拥坛,并支持自動(dòng)重連蓬蝶,OkHttp的優(yōu)點(diǎn)遠(yuǎn)不止于此,所以Retrofit2選擇用OkHttp作為網(wǎng)絡(luò)請(qǐng)求執(zhí)行器是一個(gè)再明智不過(guò)的決定猜惋。
如果你想異步的執(zhí)行網(wǎng)絡(luò)請(qǐng)求丸氛,最簡(jiǎn)單的就是在Activity或者Fragment中View控件的監(jiān)聽(tīng)器中進(jìn)行網(wǎng)絡(luò)訪問(wèn),并通過(guò)call.enqueue()
處理請(qǐng)求結(jié)果著摔,并更新UI缓窜,下面是一個(gè)小demo:
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
GitHubService gitHubService = GitHubService.retrofit.create(GitHubService.class);
final Call<List<Contributor>> call =
gitHubService.repoContributors("square", "retrofit");
call.enqueue(new Callback<List<Contributor>>() {
@Override
public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
final TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(response.body().toString());
}
@Override
public void onFailure(Call<List<Contributor>> call, Throwable t) {
final TextView textView = (TextView) findViewById(R.id.textView);
textView.setText("Something went wrong: " + t.getMessage());
}
});
}
});
如果你需要在工作線程中執(zhí)行網(wǎng)絡(luò)請(qǐng)求,而不是在一個(gè)Activity或者一個(gè)Fragment中去執(zhí)行谍咆,那么也就意味著禾锤,你可以在同一個(gè)線程中同步的去執(zhí)行網(wǎng)絡(luò)請(qǐng)求,使用call.execute()
方法來(lái)處理請(qǐng)求結(jié)果即可摹察,代碼如下:
try {
Response<User> response = call.execute();
} catch (IOException e ){
// handle error
}
0X03 Retrofit2+RxJava實(shí)現(xiàn)開(kāi)發(fā)效率最大化
Retorfit是支持RxJava恩掷,Guava,Java8 等等一系列擴(kuò)展的供嚎,關(guān)于RxJava這個(gè)網(wǎng)紅我就不做介紹了黄娘,RactiveX項(xiàng)目對(duì) JVM 的擴(kuò)展,你可以把它當(dāng)做一個(gè)超級(jí)強(qiáng)大的異步事件處理庫(kù)克滴,可他的NB之處遠(yuǎn)不止于此逼争,至少做Android的都應(yīng)該聽(tīng)過(guò)他的鼎鼎大名,不熟悉的可以去看看RxJava WikiH芭狻誓焦!而這里Retrofit2+RxJava
組合就可以實(shí)現(xiàn)開(kāi)發(fā)效率的大幅提升,至于怎樣提升的望忆?對(duì)比一下你以前寫(xiě)的網(wǎng)絡(luò)請(qǐng)求的代碼量就知道了罩阵!結(jié)合一個(gè)實(shí)踐項(xiàng)目的源碼來(lái)分析,這里是請(qǐng)求果殼網(wǎng)最新的100條文章數(shù)據(jù)启摄,返回結(jié)果為Json,首先build.gradle
添加依賴:
compile 'io.reactivex:rxandroid:1.1.0' // RxAndroid
compile 'io.reactivex:rxjava:1.1.0' // 推薦同時(shí)添加RxJava
compile 'com.squareup.retrofit2:retrofit:2.1.0' // Retrofit網(wǎng)絡(luò)處理
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' // Retrofit的rx解析庫(kù)
compile 'com.squareup.retrofit2:converter-gson:2.1.0' // Retrofit的gson庫(kù)
compile 'com.squareup.okhttp3:okhttp:3.2.0' // OkHttp3
第一步幽钢,定義服務(wù)器Json數(shù)據(jù)對(duì)應(yīng)的POJO類歉备,這里我們可以偷一下懶可以直接通過(guò)jsonschema2pojo 這個(gè)網(wǎng)站自動(dòng)生成POJO類,就不用我們手動(dòng)去寫(xiě)了匪燕,然后copy到項(xiàng)目目錄的bean包下蕾羊。接著便是定義HTTP請(qǐng)求方法了喧笔,以接口的形式定義,如下:
// 服務(wù)器數(shù)據(jù)對(duì)應(yīng)的實(shí)體類
public class Guokr {
// 定義序列化后的名字
public @SerializedName("ok") Boolean response_ok;
// 定義序列化后的名字
public @SerializedName("result") List<GuokrResult> response_results;
public static class GuokrResult {
public int id;
public String title;
public String headline_img_tb; // 用于文章列表頁(yè)小圖
public String headline_img; // 用于文章內(nèi)容頁(yè)大圖
public String link;
public String author;
public String summary;
}
}
// HTTP請(qǐng)求方法
public interface GuokrService {
@GET("handpick/article.json")
Observable<Guokr> getGuokrs(@Query("retrieve_type") String type,
@Query("category") String category,
@Query("limit") int limit,
@Query("ad") int ad);
}
其中 Observable<Guokr>
是RxJava中的被觀察者龟再,對(duì)應(yīng)請(qǐng)求結(jié)果Call<T>
书闸。只是因?yàn)镽etrofit提供了非常強(qiáng)大的CallAdapterFactory
完美兼容了RxJava
這個(gè)超級(jí)大網(wǎng)紅,才導(dǎo)致我們平忱眨看到的寫(xiě)法是這樣的浆劲。第二步, 需要通過(guò)Retrofit.builder()
創(chuàng)建 GuokrService
接口對(duì)象哀澈,通過(guò)接口對(duì)象執(zhí)行 getGuokrs
方法進(jìn)行網(wǎng)絡(luò)訪問(wèn)牌借,代碼如下:
// 封裝 GuokrService 請(qǐng)求
public static GuokrService getGuokrService() {
if (guokrService == null) {
Retrofit retrofit = new Retrofit.Builder()
.client(mClient)
.baseUrl("http://apis.guokr.com/")
.addCallAdapterFactory(rxJavaCallAdapterFactory)
.addConverterFactory(gsonConverterFactory)
.build();
guokrService = retrofit.create(GuokrService.class);
}
return guokrService;
}
// 默認(rèn)加載最新的100條數(shù)據(jù)
subscription = RetrofitClient.getGuokrService().getGuokrs("by_since", "all", 100, 1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Guokr>() {
@Override
public void onCompleted() {
Log.e(TAG, "--------completed-------");
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "--------error-------");
Log.e(TAG, e.getMessage());
}
@Override
public void onNext(Guokr guokr) {
if (guokr.response_ok) {
List<Guokr.GuokrResult> guokrResults = guokr.response_results;
List<GuokrItem> guokrItems = new ArrayList<>(guokrResults.size());
for (Guokr.GuokrResult result : guokrResults) {
GuokrItem item = new GuokrItem();
item.headline_img_tb = result.headline_img_tb;
item.title = result.title;
item.id = result.id;
item.headline_img = result.headline_img;
item.summary = result.summary;
guokrItems.add(item);
}
mAdapter.addAll(guokrItems);
mAdapter.notifyDataSetChanged();
});
注意到封裝 GuokrService 請(qǐng)求:
-
addCallAdapterFactory(rxJavaCallAdapterFactory)
方法指定使用RxJava
作為CallAdapter
割按,需要傳入一個(gè)RxJavaCallAdapterFactory
對(duì)象:CallAdapter.Factory rxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create()
膨报; -
addConverterFactory(gsonConverterFactory)
方法指定Gson
作為解析Json數(shù)據(jù)的Converter
:Converter.Factory gsonConverterFactory = GsonConverterFactory.create()
; -
client(mClient)
方法指定網(wǎng)絡(luò)執(zhí)行器為OkHttp
如下創(chuàng)建一個(gè)默認(rèn)的OkHttp對(duì)象傳入即可:OkHttpClient mClient = new OkHttpClient()
适荣;
而加載網(wǎng)絡(luò)數(shù)據(jù)這個(gè)鏈?zhǔn)秸{(diào)用就是RxJava最大的特色现柠,用在這里邏輯就是,被觀察者Observable<Guokr>
訂閱觀察者Observer<Guokr>
弛矛,當(dāng)服務(wù)器一有response够吩,觀察者就會(huì)立即處理response result。因?yàn)?code>RxJava最大的亮點(diǎn)就是異步汪诉,可以很方便的切換當(dāng)前任務(wù)所在的線程废恋,并能對(duì)事件流進(jìn)行各種Map變換,比如壓合扒寄、轉(zhuǎn)換鱼鼓、緩存等操作。這里是最基本的用法该编,被觀察者直接把事件流訂閱到觀察者迄本,中間沒(méi)有做轉(zhuǎn)換處理。
到此網(wǎng)絡(luò)訪問(wèn)就完成了课竣,是不是很簡(jiǎn)潔嘉赎?簡(jiǎn)潔就對(duì)了,那是因?yàn)樘鄸|西Retrofit2和RxJava甚至是OkHttp都幫我們做好了于樟!再回顧一下整個(gè)網(wǎng)絡(luò)訪問(wèn)流程:創(chuàng)建Bean類 --> 創(chuàng)建接口形式的http
請(qǐng)求方法 --> 通過(guò)Retrofit.builder()
創(chuàng)建接口對(duì)象并調(diào)用http
方法請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù) --> 在RxJava
的Observable
中異步處理請(qǐng)求結(jié)果公条!
0X04 自定義OkHttp Interceptor實(shí)現(xiàn)日志輸出,保存和添加Cookie
在Retrofit2做網(wǎng)絡(luò)請(qǐng)求的第二步迂曲,我們需要通過(guò)Retrofit.builder()
方法來(lái)創(chuàng)建Retrofit
對(duì)象靶橱,其中client(mClient)
這個(gè)方法指定一個(gè)OkHttpClient
客戶端作為請(qǐng)求的執(zhí)行器,需要傳入一個(gè)OkHttpClient
對(duì)象作為參數(shù),那么在這里关霸,我們就可以進(jìn)行一些OkHttp相關(guān)的操作传黄,比如自定義Interceptor
,通過(guò)自定義Interceptor
可以實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求日志的分級(jí)輸出队寇,可以實(shí)現(xiàn)保存和添加Cookie這些功能膘掰,當(dāng)然,這些功能的實(shí)現(xiàn)都是基于OkHttp佳遣,所以要對(duì)OkHttp有一定的了解才能靈活運(yùn)用识埋。
Retrofit使用指南-->OkHttp配合Retrofit使用 這篇博客在OkHttp配合Retrofit使用這一節(jié),關(guān)于OkHttpClient添加HttpLoggingInterceptor
進(jìn)行日志輸出苍日,以及如何設(shè)置SslSocketFactory做了詳細(xì)的說(shuō)明惭聂,有興趣的同學(xué)可以參考!值得注意的是相恃,如果后一次請(qǐng)求的URL辜纲,需要從前一次請(qǐng)求結(jié)果數(shù)據(jù)中獲取,這時(shí)候就需要?jiǎng)討B(tài)的改變BaseURL拦耐,也可通過(guò)自定義Interceptor
來(lái)實(shí)現(xiàn)這一需求耕腾,在BaseURL改變時(shí),只需要setHost()
就可以讓下次請(qǐng)求的BaseURL改變杀糯,代碼如下:
public class DynamicBaseUrlInterceptor implements Interceptor {
private volatile String host;
public void setHost(String host) {
this.host = host;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (!TextUtils.isEmpty(host)) {
HttpUrl newUrl = originalRequest.url().newBuilder()
.host(host)
.build();
originalRequest = originalRequest.newBuilder()
.url(newUrl)
.build();
}
return chain.proceed(originalRequest);
}
}
那么怎樣在通過(guò)OkHttp保存和添加Cookie呢扫俺?其實(shí)實(shí)現(xiàn)原理和上面添加日志攔截器差不多,只是添加的Intercepter
不同而已固翰,其實(shí)就是自定義了一個(gè)Interceptor
接口實(shí)現(xiàn)類狼纬,接收和保存返回結(jié)果中的Cookie,或者添加Cookie骂际,最后疗琉,在創(chuàng)建OkHttp實(shí)例的時(shí)候,傳入以上Interceptor
實(shí)現(xiàn)類的對(duì)象即可歉铝。Retrofit使用OkHttp保存和添加cookie這篇博客講的很好盈简,可以作為參考!
簡(jiǎn)而言之太示,以上這Retorfit2些高級(jí)運(yùn)用都是基于定制化OkHttp來(lái)實(shí)現(xiàn)的柠贤,如果想玩得很溜就必須對(duì)OkHttp了解一二,推薦看這篇博客OkHttp3源碼分析綜述类缤!最起碼需要弄清楚OkHttpClient自定義Interceptor這一塊內(nèi)容臼勉,推薦看OkHttp Github Wiki --> Interceptors!
0X05 自定義ResponseConverter餐弱,自定義HTTP請(qǐng)求注解
默認(rèn)情況下坚俗,Retrofit會(huì)把HTTP響應(yīng)體反序列化到OkHttp的ResponseBody
中镜盯,加入Converter可以將返回的數(shù)據(jù)直接格式化成你需要的樣子岸裙,Retrofit提供了如下6個(gè)Converter可以直接使用猖败,使用前需要加上相應(yīng)的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
在前面Retrofit2+RxJava實(shí)例中,我們指定GsonConverterFactory作為解析Json數(shù)據(jù)的Converter降允,當(dāng)面對(duì)更復(fù)雜的需求時(shí)恩闻,仍然可以通過(guò)繼承Converter.Factory
來(lái)自定義Converter,只需要重寫(xiě)以下這兩個(gè)方法即可:
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
//your own implements
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
//your own implements
}
我們不妨來(lái)看看GsonConverterFactory
源碼剧董,果然GsonConverterFactory
也是繼承Converter.Factory
來(lái)實(shí)現(xiàn)的幢尚,重寫(xiě)了responseBodyConverter
和 requestBodyConverter
這兩個(gè)方法,代碼只有70多行還是很簡(jiǎn)潔的翅楼,如下:
public final class GsonConverterFactory extends Converter.Factory {
/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create() {
return create(new Gson());
}
/**
* Create an instance using {@code gson} for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create(Gson gson) {
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
這里需要詳細(xì)解釋一下TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type))
中的TypeAdapter<?>
尉剩,TypeAdapte
是Gson提供的自定義Json解析器,Type就是HTTP請(qǐng)求接口GuokrService
中getGuokrs()
方法返回值的泛型類型毅臊,如果返回值類型是Call<T>
理茎,那么這里的Type就是泛型類型 T ,如果返回值類型是Observable<List<Guokr>>
管嬉,那么Type就是List<Guokr>
皂林;關(guān)于Gson的詳細(xì)用法可以參考:你真的會(huì)用Gson嗎?Gson使用指南(四)。
我們看到responseBodyConverter
方法返回的是一個(gè)GsonResponseBodyConverter
對(duì)象蚯撩,跟進(jìn)去看一下GsonResponseBodyConverter
源碼础倍,也很簡(jiǎn)單,源碼 如下:
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
我們看到GsonResponseBodyConverter<T>
實(shí)現(xiàn)了Converter<ResponseBody, T>
胎挎,重寫(xiě)了convert(ResponseBody value)
方法沟启,這就給我們提供了一個(gè)思路:自定義Converter關(guān)鍵一步就是要實(shí)現(xiàn)Converter<ResponseBody, T>
接口并且重寫(xiě)convert(ResponseBody value)
方法,具體重寫(xiě)的代碼我就不貼出來(lái)了犹菇,可以參考如何使用Retrofit請(qǐng)求非Restful API 這篇博客自定義Converter的做法德迹!
另外,如果需求更復(fù)雜项栏,需要我們自定義HTTP請(qǐng)求方法的注解浦辨,又該怎么做呢?我們還注意到GsonConverterFactory
類的重寫(xiě)方法responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit)
中的Annotation[] methodAnnotations
這個(gè)參數(shù)沼沈,對(duì)的流酬,或許你已經(jīng)猜到了,這就是我們?cè)贖TTP請(qǐng)求接口方法中定義的注解列另,先看 @GET
注解的源碼芽腾,如下:
/** Make a GET request. */
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
String value() default "";
}
那我們自定義注解的思路也就有了,模仿上面 @GET
注解寫(xiě)一個(gè) @WONDERTWO
注解即可页衙。這里我點(diǎn)到即止摊滔,主要是提供一種思路阴绢,具體實(shí)現(xiàn)仍然可以參考上面提到的 如何使用Retrofit請(qǐng)求非Restful API 這篇博客自定義HTTP請(qǐng)求注解的做法!
0X06 寫(xiě)在后面
有一個(gè)結(jié)論說(shuō)的是在網(wǎng)絡(luò)上艰躺,只有 1% 的用戶貢獻(xiàn)了內(nèi)容呻袭,10% 的用戶比較活躍,會(huì)評(píng)論和點(diǎn)贊腺兴,剩下的都是網(wǎng)絡(luò)透明人左电,他們只是默默地在看,既不貢獻(xiàn)內(nèi)容页响,也不點(diǎn)贊篓足。這篇文章希望能讓你成為網(wǎng)絡(luò)上貢獻(xiàn)內(nèi)容的 TOP 1%。如果暫時(shí)做不到闰蚕,那就先點(diǎn)個(gè)贊吧栈拖,成為活躍的 10%。
參考文獻(xiàn)
- Retrofit官方文檔
- Getting started with Retrofit 2
- Consuming APIs with Retrofit
- Retrofit 2.0: The biggest update yet on the best HTTP Client Library for Android
- Retrofit使用指南
- Square全家桶正傳——Retrofit使用及配合RxJava實(shí)現(xiàn)最大效率開(kāi)發(fā)
- Retrofit使用OkHttp保存和添加cookie
- 如何使用Retrofit請(qǐng)求非Restful API
- Retrofit請(qǐng)求參數(shù)注解字段說(shuō)明
- OkHttp-->Interceptors