retrofit 解析百度地图api 返回数据_阿里二面:关于 Retrofit 你知道多少?看完你的offer稳了
一、整體思路
從使用方法出發(fā),首先是怎么使用,其次是我們使用的功能在內(nèi)部是如何實(shí)現(xiàn)的, 實(shí)現(xiàn)方案上有什么技巧,有什么范式。全文基本上是對(duì) Retrofit 源碼的一個(gè)分析與 導(dǎo)讀,非常建議大家下載 Retrofit 源碼之后,跟著本文,過(guò)一遍源碼。
二、基本用例
2.1 創(chuàng)建 Retrofit 對(duì)象
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .build();2.2 定義 API 并獲取 API 實(shí)例
public interface GitHubService { @GET("users/{user}/repos") Call> listRepos(@Path("user") String user); } GitHubService github = retrofit.create(GitHubService.class);先看定義,非常簡(jiǎn)潔,也沒(méi)有什么特別之處,除了兩個(gè)注解:@GET和 @Path 。它們的用處稍后再分析,我們接著看創(chuàng)建 API 實(shí) 例: retrofit.create(GitHubService.class) 。這樣就創(chuàng)建了 API 實(shí)例了, 就可以調(diào)用 API 的方法發(fā)起 HTTP 網(wǎng)絡(luò)請(qǐng)求了,太方便了。 但 create 方法是怎么創(chuàng)建 API 實(shí)例的呢?
public T create(final Class service) { // 省略非關(guān)鍵代碼 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object ... args) throws Throwable { // 先省略實(shí)現(xiàn) } }); }創(chuàng)建 API 實(shí)例使用的是動(dòng)態(tài)代理技術(shù)。
簡(jiǎn)而言之,就是動(dòng)態(tài)生成接口的實(shí)現(xiàn)類(當(dāng)然生成實(shí)現(xiàn)類有緩存機(jī)制),并創(chuàng)建其 實(shí)例(稱之為代理),代理把對(duì)接口的調(diào)用轉(zhuǎn)發(fā)給 InvocationHandler 實(shí)例, 而在 InvocationHandler 的實(shí)現(xiàn)中,除了執(zhí)行真正的邏輯(例如再次轉(zhuǎn)發(fā)給真 正的實(shí)現(xiàn)類對(duì)象),我們還可以進(jìn)行一些有用的操作,例如統(tǒng)計(jì)執(zhí)行時(shí)間、進(jìn)行初 始化和清理、對(duì)接口調(diào)用進(jìn)行檢查等。 為什么要用動(dòng)態(tài)代理?因?yàn)閷?duì)接口的所有方法的調(diào)用都會(huì)集中轉(zhuǎn)發(fā)到 InvocationHandler#invoke 函數(shù)中,我們可以集中進(jìn)行處理,更方便了。你可 能會(huì)想,我也可以手寫這樣的代理類,把所有接口的調(diào)用都轉(zhuǎn)發(fā)到 InvocationHandler#invoke 呀,當(dāng)然可以,但是可靠地自動(dòng)生成豈不更方便?
2.3 調(diào)用 API 方法
獲取到 API 實(shí)例之后,調(diào)用方法和普通的代碼沒(méi)有任何區(qū)別:
Call> call = github.listRepos("square"); List repos = call.execute().body();這兩行代碼就發(fā)出了 HTTP 請(qǐng)求,并把返回的數(shù)據(jù)轉(zhuǎn)化為了 List,太方 便了!
現(xiàn)在我們來(lái)看看調(diào)用 listRepos 是怎么發(fā)出 HTTP 請(qǐng)求的。上面 Retrofit#create 方法返回時(shí)省略的代碼如下:
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, Object.. . args) throws Throwable { // If the method is a method from Object then defer to n ormal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, p roxy, args); } ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } });如果調(diào)用的是 Object 的方法,例如 equals, toString,那就直接調(diào)用。 如果是 default 方法(Java 8 引入),就調(diào)用 default 方法。這些我們都先不管,因 為我們?cè)诎沧科脚_(tái)調(diào)用 listRepos ,肯定不是這兩種情況,那這次調(diào)用真正干活 的就是這三行代碼了(好好記住這三行代碼,因?yàn)榻酉聛?lái)很長(zhǎng)的篇幅都是在講它們 :) ):
ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall);在繼續(xù)分析這三行代碼之前,先看一個(gè)流程圖
這三行代碼基本就是對(duì)應(yīng)于流程圖中軸上部了, ServiceMethod , build OkHttpCall, CallAdapter adapt。
2.4 ServiceMethod
ServiceMethod 類的作用正如其 JavaDoc所言:
Adapts an invocation of an interface method into an HTTP call. 把對(duì)接口方法 的調(diào)用轉(zhuǎn)為一次 HTTP 調(diào)用。
一個(gè) ServiceMethod 對(duì)象對(duì)應(yīng)于一個(gè) API interface 的一個(gè)方 法, loadServiceMethod(method) 方法負(fù)責(zé)加載 ServiceMethod :
ServiceMethod loadServiceMethod(Method method) { ServiceMethod result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder(this, method).build(); serviceMethodCache.put(method, result); } } return result; }這里實(shí)現(xiàn)了緩存邏輯,同一個(gè) API 的同一個(gè)方法,只會(huì)創(chuàng)建一次。這里由于我們每 次獲取 API 實(shí)例都是傳入的 class 對(duì)象,而 class 對(duì)象是進(jìn)程內(nèi)單例的,所 以獲取到它的同一個(gè)方法 Method 實(shí)例也是單例的,所以這里的緩存是有效的。
我們?cè)倏纯?ServiceMethod 的構(gòu)造函數(shù):
ServiceMethod(Builder builder) { this.callFactory = builder.retrofit.callFactory(); this.callAdapter = builder.callAdapter; this.baseUrl = builder.retrofit.baseUrl(); this.responseConverter = builder.responseConverter; this.httpMethod = builder.httpMethod; this.relativeUrl = builder.relativeUrl; this.headers = builder.headers; this.contentType = builder.contentType; this.hasBody = builder.hasBody; this.isFormEncoded = builder.isFormEncoded; this.isMultipart = builder.isMultipart; this.parameterHandlers = builder.parameterHandlers; }成員很多,但這里我們重點(diǎn)關(guān)注四個(gè)成 員: callFactory, callAdapter , responseConverter 和 parameterHandlers 。
1.callFactory 負(fù)責(zé)創(chuàng)建 HTTP 請(qǐng)求,HTTP 請(qǐng)求被抽象為了okhttp3.Call 類,它表示一個(gè)已經(jīng)準(zhǔn)備好,可以隨時(shí)執(zhí)行的 HTTP 請(qǐng)求;
2.callAdapter 把 retrofit2.Call轉(zhuǎn)為 T (注意和 okhttp3.Call 區(qū)分開來(lái),retrofit2.Call表示的是對(duì)一個(gè) Retrofit 方法的調(diào)用),這個(gè)過(guò)程會(huì)發(fā)送一個(gè) HTTP 請(qǐng)求,拿到服務(wù)器返回的數(shù)據(jù)(通 過(guò) okhttp3.Call實(shí)現(xiàn)),并把數(shù)據(jù)轉(zhuǎn)換為聲明的 T 類型對(duì)象(通過(guò) Converter 實(shí)現(xiàn));
3.responseConverter 是 Converter 類型,負(fù)責(zé)把服 務(wù)器返回的數(shù)據(jù)(JSON、XML、二進(jìn)制或者其他格式,由 ResponseBody封裝)轉(zhuǎn)化為 T 類型的對(duì)象;
4.parameterHandlers 則負(fù)責(zé)解析 API 定義時(shí)每個(gè)方法的參數(shù),并在構(gòu)造 HTTP 請(qǐng)求時(shí)設(shè)置參數(shù);
它們的使用稍后再分析,這里先看看它們的創(chuàng)建(代碼比較分散,就不貼太多代碼 了,大多是結(jié)論):
2.4.1 callFactory
this.callFactory = builder.retrofit.callFactory(),所以 callFactory 實(shí)際上由 Retrofit 類提供,而我們?cè)跇?gòu)造 Retrofit 對(duì)象 時(shí),可以指定 callFactory,如果不指定,將默認(rèn)設(shè)置為一個(gè) okhttp3.OkHttpClient。
2.4.2 callAdapter
private CallAdapter> createCallAdapter() { // 省略檢查性代碼 Annotation[] annotations = method.getAnnotations(); try { return retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, "Unable to create call adapter for %s", returnType); } }可以看到, callAdapter 還是由 Retrofit 類提供。在 Retrofit 類內(nèi)部, 將遍歷一個(gè) CallAdapter.Factory 列表,讓工廠們提供,如果最終沒(méi)有工廠能 (根據(jù) returnType 和 annotations)提供需要的 CallAdapter ,那將拋出 異常。而這個(gè)工廠列表我們可以在構(gòu)造 Retrofit 對(duì)象時(shí)進(jìn)行添加。
2.4.3, responseConverter
private Converter createResponseConverter() { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotati ons); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, "Unable to create converter for %s", re sponseType); } }同樣, responseConverter 還是由 Retrofit 類提供,而在其內(nèi)部,邏輯和創(chuàng) 建 callAdapter 基本一致,通過(guò)遍歷 Converter.Factory列表,看看有沒(méi)有 工廠能夠提供需要的 responseBodyConverter。工廠列表同樣可以在構(gòu)造 Retrofit 對(duì)象時(shí)進(jìn)行添加。
2.4.4 parameterHandlers
每個(gè)參數(shù)都會(huì)有一個(gè) ParameterHandler ,由 ServiceMethod#parseParameter 方法負(fù)責(zé)創(chuàng)建,其主要內(nèi)容就是解析每個(gè)參數(shù) 使用的注解類型(諸如 Path , Query , Field 等),對(duì)每種類型進(jìn)行單獨(dú)的 處理。構(gòu)造 HTTP 請(qǐng)求時(shí),我們傳遞的參數(shù)都是字符串,那 Retrofit 是如何把我們 傳遞的各種參數(shù)都轉(zhuǎn)化為 String 的呢?還是由 Retrofit 類提供 converter!
Converter.Factory 除了提供上一小節(jié)提到的 responseBodyConverter,還提 供 requestBodyConverter和 stringConverter,API 方法中除了 @Body 和 @Part 類型的參數(shù),都利用 stringConverter 進(jìn)行轉(zhuǎn)換,而 @Body 和 @Part 類型的參數(shù)則利用 requestBodyConverter 進(jìn)行轉(zhuǎn)換。
這三種 converter 都是通過(guò)“詢問(wèn)”工廠列表進(jìn)行提供,而工廠列表我們可以在構(gòu)造 Retrofit 對(duì)象時(shí)進(jìn)行添加。
2.4.5 工廠讓各個(gè)模塊得以高度解耦
上面提到了三種工廠: okhttp3.Call.Factory , CallAdapter.Factory 和 Converter.Factory ,分別負(fù)責(zé)提供不同的模塊,至于怎么提供、提供何種模 塊,統(tǒng)統(tǒng)交給工廠,Retrofit 完全不摻和,它只負(fù)責(zé)提供用于決策的信息,例如參 數(shù)/返回值類型、注解等。
這不正是我們苦苦追求的高內(nèi)聚低耦合效果嗎?解耦的第一步就是面向接口編程, 模塊之間、類之間通過(guò)接口進(jìn)行依賴,創(chuàng)建怎樣的實(shí)例,則交給工廠負(fù)責(zé),工廠同 樣也是接口,添加(Retrofit doc 中使用 install 安裝一詞,非常貼切)怎樣的工 廠,則在最初構(gòu)造 Retrofit 對(duì)象時(shí)決定,各個(gè)模塊之間完全解耦,每個(gè)模塊只 專注于自己的職責(zé),全都是套路,值得反復(fù)玩味、學(xué)習(xí)與模仿。
除了上面重點(diǎn)分析的這四個(gè)成員, ServiceMethod 中還包含了 API 方法的 url 解 析等邏輯,包含了眾多關(guān)于泛型和反射相關(guān)的代碼,有類似需求的時(shí)候,也非常值 得學(xué)習(xí)模仿
2.5 OkHttpCall
終于把 ServiceMethod 看了個(gè)大概,接下來(lái)我們看看 OkHttpCall 。 OkHttpCall 實(shí)現(xiàn)了 retrofit2.Call ,我們通常會(huì)使用它的 execute() 和 enqueue(Callback callback) 接口。前者用于同步執(zhí)行 HTTP 請(qǐng)求,后者 用于異步執(zhí)行。
2.5.1,先看 execute()
@Override public Response execute() throws IOException { okhttp3.Call call; synchronized (this) { // 省略部分檢查代碼 call = rawCall; if (call == null) { try { call = rawCall = createRawCall(); } catch (IOException | RuntimeException e) { creationFailure = e; throw e; } } } return parseResponse(call.execute()); ...... }主要包括三步:
創(chuàng)建 okhttp3.Call ,包括構(gòu)造參數(shù);執(zhí)行網(wǎng)絡(luò)請(qǐng)求;解析網(wǎng)絡(luò)請(qǐng)求返回的數(shù)據(jù);
createRawCall() 函數(shù)中,我們調(diào)用了 serviceMethod.toRequest(args) 來(lái)創(chuàng)建 okhttp3.Request ,而在后者中,我們之前準(zhǔn)備好的 parameterHandlers 就派上了用場(chǎng)。
然后我們?cè)僬{(diào)用 serviceMethod.callFactory.newCall(request) 來(lái)創(chuàng)建 okhttp3.Call ,這里之前準(zhǔn)備好的 callFactory 同樣也派上了用場(chǎng),由于工 廠在構(gòu)造 Retrofit 對(duì)象時(shí)可以指定,所以我們也可以指定其他的工廠(例如使 用過(guò)時(shí)的 HttpURLConnection 的工廠),來(lái)使用其它的底層 HttpClient 實(shí)現(xiàn)。
我們調(diào)用 okhttp3.Call#execute() 來(lái)執(zhí)行網(wǎng)絡(luò)請(qǐng)求,這個(gè)方法是阻塞的,執(zhí)行 完畢之后將返回收到的響應(yīng)數(shù)據(jù)。收到響應(yīng)數(shù)據(jù)之后,我們進(jìn)行了狀態(tài)碼的檢查, 通過(guò)檢查之后我們調(diào)用了 serviceMethod.toResponse(catchingBody) 來(lái)把響 應(yīng)數(shù)據(jù)轉(zhuǎn)化為了我們需要的數(shù)據(jù)類型對(duì)象。在 toResponse 函數(shù)中,我們之前準(zhǔn) 備好的 responseConverter 也派上了用場(chǎng)。
好了,之前準(zhǔn)備好的東西都派上了用場(chǎng),還好沒(méi)有白費(fèi) :)
2.5.2 再看 enqueue(Callback callback)
這里的異步交給了 okhttp3.Call#enqueue(Callback responseCallback) 來(lái) 實(shí)現(xiàn),并在它的 callback 中調(diào)用 parseResponse 解析響應(yīng)數(shù)據(jù),并轉(zhuǎn)發(fā)給傳入 的 callback。
2.6 CallAdapter
終于到了最后一步了, CallAdapter#adapt(Call call) 函數(shù)負(fù)責(zé)把 retrofit2.Call 轉(zhuǎn)為 T 。這里 T 當(dāng)然可以就是 retrofit2.Call ,這時(shí)我們直接返回參數(shù)就可以了,實(shí)際上這正是 DefaultCallAdapterFactory創(chuàng)建的 CallAdapter 的行為。至于其他類型的 工廠返回的 CallAdapter 的行為,這里暫且不表,后面再單獨(dú)分析。
至此,一次對(duì) API 方法的調(diào)用是如何構(gòu)造并發(fā)起網(wǎng)絡(luò)請(qǐng)求、以及解析返回?cái)?shù)據(jù),這 整個(gè)過(guò)程大致是分析完畢了。對(duì)整個(gè)流程的概覽非常重要,結(jié)合 stay 畫的流程圖, 應(yīng)該能夠比較輕松地看清整個(gè)流程了。
雖然我們還沒(méi)分析完,不過(guò)也相當(dāng)于到了萬(wàn)里長(zhǎng)征的遵義,終于可以舒一口氣了 :)
三、retrofit-adapters 模塊
retrofit 模塊內(nèi)置了 DefaultCallAdapterFactory 和 ExecutorCallAdapterFactory ,它們都適用于 API 方法得到的類型為 retrofit2.Call 的情形,前者生產(chǎn)的 adapter 啥也不做,直接把參數(shù)返回,后 者生產(chǎn)的 adapter 則會(huì)在異步調(diào)用時(shí)在指定的 Executor 上執(zhí)行回調(diào)。
retrofit-adapters 的各個(gè)子模塊則實(shí)現(xiàn)了更多的工 廠: GuavaCallAdapterFactory , Java8CallAdapterFactory 和 RxJavaCallAdapterFactory 。這里我主要分析 RxJavaCallAdapterFactory ,下面的內(nèi)容就需要一些 RxJava 的知識(shí)了,不過(guò) 我想使用 Retrofit 的你,肯定也在使用RxJava :)
RxJavaCallAdapterFactory#get 方法中對(duì)返回值的類型進(jìn)行了檢查,只支持 rx.Single , rx.Completable 和 rx.Observable ,這里我主要關(guān)注對(duì) rx.Observable 的支持。
RxJavaCallAdapterFactory#getCallAdapter 方法中對(duì)返回值的泛型類型進(jìn)行 了進(jìn)一步檢查,例如我們聲明的返回值類型為 Observable>,泛型 類型就是 List ,這里對(duì) retrofit2.Response 和retrofit2.adapter.rxjava.Result 進(jìn)行了特殊處理,有單獨(dú)的 adapter 負(fù)責(zé) 進(jìn)行轉(zhuǎn)換,其他所有類型都由 SimpleCallAdapter負(fù)責(zé)轉(zhuǎn)換。
那我們就來(lái)看看 SimpleCallAdapter#adapt :
@Override public Observable adapt(Call call) { Observable observable = Observable.create(new CallOnSubscri be<>(call)) .lift(OperatorMapResponseToBodyOrError.instance()); if (scheduler != null) { return observable.subscribeOn(scheduler); } return observable; }這里創(chuàng)建了一個(gè) Observable ,它的邏輯由 CallOnSubscribe 類實(shí)現(xiàn),同時(shí)使 用了一個(gè) OperatorMapResponseToBodyOrError 操作符,用來(lái)把 retrofit2.Response 轉(zhuǎn)為我們聲明的類型,或者錯(cuò)誤異常類型。
我們接著看 CallOnSubscribe#call :
@Override public void call(final Subscriber super Response> subscribe r) { // Since Call is a one-shot type, clone it for each new subscr iber. Call call = originalCall.clone(); // Wrap the call in a helper which handles both unsubscription and backpressure. RequestArbiter requestArbiter = new RequestArbiter<>(call, subscriber); subscriber.add(requestArbiter); subscriber.setProducer(requestArbiter); }代碼很簡(jiǎn)短,只干了三件事:
clone 了原來(lái)的 call,因?yàn)?okhttp3.Call 是只能用一次的,所以每次都是 新 clone 一個(gè)進(jìn)行網(wǎng)絡(luò)請(qǐng)求;創(chuàng)建了一個(gè)叫做 RequestArbiter 的 producer,別被它的名字嚇懵了,它就 是個(gè) producer;把這個(gè) producer設(shè)置給 subscriber;
簡(jiǎn)言之,大部分情況下 Subscriber 都是被動(dòng)接受 Observable push 過(guò)來(lái)的數(shù)據(jù), 但要是 Observable發(fā)得太快,Subscriber 處理不過(guò)來(lái),那就有問(wèn)題了,所以就有 了一種 Subscriber 主動(dòng) pull 的機(jī)制,而這種機(jī)制就是通過(guò) Producer 實(shí)現(xiàn)的。給 Subscriber 設(shè)置 Producer 之后(通過(guò) Subscriber#setProducer 方法), Subscriber 就會(huì)通過(guò) Producer 向上游根據(jù)自己的能力請(qǐng)求數(shù)據(jù)(通過(guò) Producer#request 方法),而 Producer 收到請(qǐng)求之后(通常都是 Observable 管理 Producer,所以“相當(dāng)于”就是 Observable 收到了請(qǐng)求),再根據(jù)請(qǐng)求的量給 Subscriber 發(fā)數(shù)據(jù)。
那我們就看看 RequestArbiter#request:
@Override public void request(long n) { if (n < 0) throw new IllegalArgumentException("n < 0: " + n); if (n == 0) return; // Nothing to do when requesting 0. if (!compareAndSet(false, true)) return; // Request was alread y triggered. try { Response response = call.execute(); if (!subscriber.isUnsubscribed()) { subscriber.onNext(response); } } catch (Throwable t) { Exceptions.throwIfFatal(t); if (!subscriber.isUnsubscribed()) { subscriber.onError(t); } return; } if (!subscriber.isUnsubscribed()) { subscriber.onCompleted(); } }producer 相關(guān)的邏輯非常簡(jiǎn)單,這里就不在贅述。實(shí)際干活的邏輯就是執(zhí)行 call.execute() ,并把返回值發(fā)送給下游。
而 OperatorMapResponseToBodyOrError#call 也相當(dāng)簡(jiǎn)短:
@Override public Subscriber super Response> call(final Subscriber s uper T> child) { return new Subscriber>(child) { @Override public void onNext(Response response) { if (response.isSuccessful()) { child.onNext(response.body()); } else { child.onError(new HttpException(response)); } } @Override public void onCompleted() { child.onCompleted(); } @Override public void onError(Throwable e) { child.onError(e); } }; }關(guān)鍵就是調(diào)用了 response.body() 并發(fā)送給下游。這里, body() 返回的就是 我們聲明的泛型類型了,至于 Retrofit 是怎么把服務(wù)器返回的數(shù)據(jù)轉(zhuǎn)為我們聲明的 類型的,這就是 responseConverter的事了,還記得嗎?
最后看一張返回 Observable 時(shí)的調(diào)用棧:
執(zhí)行路徑就是:
Observable.subscribe ,觸發(fā) API 調(diào)用的執(zhí)行;CallOnSubscribe#call ,clone call,創(chuàng)建并設(shè)置 producer;RequestArbiter#request ,subscriber 被設(shè)置了 producer 之后最終調(diào)用 request,在 request 中發(fā)起請(qǐng)求,把結(jié)果發(fā)給下游;OperatorMapResponseToBodyOrError$1#onNext ,把 response的 body 發(fā) 給下游;最終就到了我們subscribe 時(shí)傳入的回調(diào)里面了;
四、retrofit-converters 模塊
retrofit 模塊內(nèi)置了 BuiltInConverters ,只能處理 ResponseBody , RequestBody 和 String 類型的轉(zhuǎn)化(實(shí)際上不需要轉(zhuǎn))。而 retrofit- converters 中的子模塊則提供了 JSON,XML,ProtoBuf 等類型數(shù)據(jù)的轉(zhuǎn)換功能, 而且還有多種轉(zhuǎn)換方式可以選擇。這里我主要關(guān)注 GsonConverterFactory 。
代碼非常簡(jiǎn)單:
@Override public Converter responseBodyConverter(Type typ e, Annotation[] annotations, Retrofit retrofit) { TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonResponseBodyConverter<>(gson, adapter); } final class GsonResponseBodyConverter implements Converter { private final Gson gson; private final TypeAdapter adapter; GsonResponseBodyConverter(Gson gson, TypeAdapter adapter) { this.gson = gson; this.adapter = adapter; } @Override public T convert(ResponseBody value) throws IOExcept ion { JsonReader jsonReader = gson.newJsonReader(value.charStream( )); try { return adapter.read(jsonReader); } finally { value.close(); } } }根據(jù)目標(biāo)類型,利用 Gson#getAdapter 獲取相應(yīng)的 adapter,轉(zhuǎn)換時(shí)利用 Gson 的 API 即可。
最后
不知不覺(jué)自己已經(jīng)做了幾年開發(fā)了,由記得剛出來(lái)工作的時(shí)候感覺(jué)自己能牛逼,現(xiàn)在回想起來(lái)感覺(jué)好無(wú)知。懂的越多的時(shí)候你才會(huì)發(fā)現(xiàn)懂的越少。
對(duì)于程序員來(lái)說(shuō),要學(xué)習(xí)的知識(shí)內(nèi)容、技術(shù)有太多太多。
很多人在剛接觸這個(gè)行業(yè)的時(shí)候或者是在遇到瓶頸期的時(shí)候,總會(huì)遇到一些問(wèn)題,比如學(xué)了一段時(shí)間感覺(jué)沒(méi)有方向感,不知道該從那里入手去學(xué)習(xí),可以關(guān)注我,每天更新各種技術(shù)干貨,分享更多最熱程序員圈內(nèi)事.
總結(jié)
以上是生活随笔為你收集整理的retrofit 解析百度地图api 返回数据_阿里二面:关于 Retrofit 你知道多少?看完你的offer稳了的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一步步Notepad变Word
- 下一篇: 用Visual C++实现远程线程嵌入技