整體Retrofit內(nèi)容如下:
- 1、Retrofit解析1之前哨站——理解RESTful
- 2工禾、Retrofit解析2之使用簡介
- 3、Retrofit解析3之反射
- 4、Retrofit解析4之注解
- 5拌蜘、Retrofit解析5之代理設(shè)計(jì)模式
- 6、Retrofit解析6之面向接口編程
- 7牙丽、Retrofit解析7之相關(guān)類解析
- 8简卧、Retrofit解析8之核心解析——ServiceMethod及注解1
- 9、Retrofit解析8之核心解析——ServiceMethod及注解2
- 10烤芦、Retrofit解析9之流程解析
- 11举娩、Retrofit解析10之感謝
從本文開始,開始正式解析Retrofit源碼构罗,本文的結(jié)構(gòu)如下:
1铜涉、解析思路
2、Call接口
3遂唧、CallAdapter接口
4芙代、Callback接口
5、Converter接口
6蠢箩、ExecutorCallAdapterFactory類
7链蕊、Platform類
8、HttpException類
9谬泌、面向接口編程
一滔韵、解析思路:
(一)、假設(shè)
在講解掌实,解析思路之前陪蜻,我們先想一下,那么想什么那贱鼻?如果讓你"設(shè)計(jì)"一個(gè)類似Retrofit的庫宴卖,你要怎么"設(shè)計(jì)"那?
注意是重點(diǎn)是 "設(shè)計(jì)" 邻悬,不是 "寫" 症昏。
那怎么 "設(shè)計(jì)" 那?那我先說我的思路父丰,如果是我肝谭,我先想摸清需求
需求如下:
- 1、首先要解耦,請(qǐng)求和構(gòu)建請(qǐng)求分離攘烛,所以必須在這里"庫"里面組建一個(gè)Call來和okHttp里面的Call對(duì)應(yīng)
- 2魏滚、有返回值的時(shí)候給外部調(diào)用的回調(diào)。
- 3坟漱、如果需要把響應(yīng)內(nèi)部的響應(yīng)體
- 4鼠次、支持響應(yīng)體自動(dòng)反序列化。
所以如果我讓我設(shè)計(jì)這么一個(gè)庫芋齿,必須先寫三個(gè)接口腥寇,每個(gè)接口對(duì)應(yīng)上面的一個(gè)問題。這里我們又想到一個(gè)Call和轉(zhuǎn)換沟突,是兩個(gè)需求花颗,根據(jù)單一原則捕传,應(yīng)該是四個(gè)接口
分別是:
- 1惠拭、一個(gè)接口表征一個(gè)HTTP請(qǐng)求
- 2、一個(gè)類型轉(zhuǎn)化接口庸论,負(fù)責(zé)本地庫的HTTP請(qǐng)求與其他類型的轉(zhuǎn)化职辅,比如轉(zhuǎn)化為RxJava,既然請(qǐng)求可以轉(zhuǎn)化聂示,那么響應(yīng)的返回值轉(zhuǎn)化也應(yīng)該在這里做域携。
- 3、序列化與反序列化操作
- 4鱼喉、響應(yīng)回調(diào)的處理
所以我在設(shè)計(jì)的時(shí)候秀鞭,肯定要設(shè)計(jì)這四個(gè)接口,然后在圍繞這四個(gè)接口進(jìn)行操作扛禽,這是我的設(shè)計(jì)思想锋边,那你們的那?
下面看下他的類目錄結(jié)構(gòu)
如上圖所示编曼,有4個(gè)接口
- Call接口
- CallAdapter接口
- Callback接口
- Converter接口
這四個(gè)接口是不是剛好對(duì)上我的那個(gè)四個(gè)接口豆巨。如果大家對(duì)面向接口編程不是很熟悉,沒關(guān)系掐场,在本篇文章的最后一部分往扔,我單獨(dú)給大家講解下,我所理解的相面接口編程熊户。那么我們先來看下這幾個(gè)接口萍膛。
二、Call接口
(一)嚷堡、思考
兩個(gè)問題:
- 1蝗罗、在看這個(gè)這接口的時(shí)候,大家想下,Retrofit為什么要?jiǎng)?chuàng)建這個(gè)接口绿饵,并且命名為Call欠肾,先思考5分鐘。再看下面的內(nèi)容拟赊。
- 2刺桃、如果讓你"設(shè)計(jì)"這個(gè)Call接口你要怎么設(shè)計(jì)
————————分割線,思考上面的問題——————————
不知道你們的想法吸祟,不過我先說下我的想法
第一個(gè)問題 我是這么想的
這個(gè)Call 肯定模擬了一個(gè)客戶端發(fā)起請(qǐng)求到服務(wù)器瑟慈,然后服務(wù)器響應(yīng)數(shù)據(jù)到客戶端的整個(gè)流程。通過這個(gè)Call我們可以獲取相應(yīng)的請(qǐng)求和相應(yīng)的信息屋匕。
第二個(gè)問題 我是這樣想的
既然是模擬了整個(gè)請(qǐng)求和響應(yīng)邏輯葛碧,所以肯定要設(shè)計(jì)一個(gè)發(fā)起請(qǐng)求的方法,來模擬發(fā)請(qǐng)求过吻;既然是請(qǐng)求进泼,所以必然包含一個(gè)同步請(qǐng)求的方法,表征同步請(qǐng)求纤虽,設(shè)計(jì)一個(gè)異步請(qǐng)求的方法乳绕,表征一個(gè)異步請(qǐng)求;還要設(shè)計(jì)一個(gè)取消請(qǐng)求的的方法逼纸,表征一個(gè)取消請(qǐng)求的方法洋措。我能想到就是這么多了,你們的那杰刽?
OK菠发,那我們來看下這個(gè)接口的源碼看下Retrofit是怎么設(shè)計(jì)的。
(二)贺嫂、來看下接口的源碼
/**
* An invocation of a Retrofit method that sends a request to a webserver and returns a response.
* Each call yields its own HTTP request and response pair. Use {@link #clone} to make multiple
* calls with the same parameters to the same webserver; this may be used to implement polling or
* to retry a failed call.
*
* <p>Calls may be executed synchronously with {@link #execute}, or asynchronously with {@link
* #enqueue}. In either case the call can be canceled at any time with {@link #cancel}. A call that
* is busy writing its request or reading its response may receive a {@link IOException}; this is
* working as designed.
*
* @param <T> Successful response body type.
*/
public interface Call<T> extends Cloneable {
/**
* Synchronously send the request and return its response.
*
* @throws IOException if a problem occurred talking to the server.
* @throws RuntimeException (and subclasses) if an unexpected error occurs creating the request
* or decoding the response.
*/
Response<T> execute() throws IOException;
/**
* Asynchronously send the request and notify {@code callback} of its response or if an error
* occurred talking to the server, creating the request, or processing the response.
*/
void enqueue(Callback<T> callback);
/**
* Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain
* #enqueue(Callback) enqueued}. It is an error to execute or enqueue a call more than once.
*/
boolean isExecuted();
/**
* Cancel this call. An attempt will be made to cancel in-flight calls, and if the call has not
* yet been executed it never will be.
*/
void cancel();
/** True if {@link #cancel()} was called. */
boolean isCanceled();
/**
* Create a new, identical call to this one which can be enqueued or executed even if this call
* has already been.
*/
Call<T> clone();
/** The original HTTP request. */
Request request();
老規(guī)矩先看下類的注釋
我簡單的翻譯一下:
通過調(diào)用Retrofit的方法向web服務(wù)器發(fā)送請(qǐng)求并返回響應(yīng)滓鸠。每一次調(diào)用都產(chǎn)生自己的HTTP請(qǐng)求和對(duì)應(yīng)的響應(yīng) 對(duì)兒。如果出現(xiàn)了在避免輪詢或者失敗重試的情況涝婉,可以 調(diào)用clone()方法 復(fù)制 可以對(duì)具有相同的web服務(wù)器進(jìn)行 具有相同參數(shù)的 請(qǐng)求哥力。
同步調(diào)用 采用execute方法,異步采用enqueue方法墩弯,在任何情況下吩跋, 一個(gè)請(qǐng)求Call 都有可以通過cancel取消,一個(gè)Call在寫入請(qǐng)求或讀取響應(yīng)的時(shí)候是可能產(chǎn)生IOExcetption的渔工,這是再正常不過的了锌钮。
參數(shù)<T> 是成功的響應(yīng)體類型
看下他的方法
和大家設(shè)計(jì)的一樣嗎?我是少了三個(gè)方法引矩,分別是
- boolean isExecuted(); 判斷是否正在運(yùn)行中
- sCanceled(); 判斷是否已經(jīng)取消了
- Call<T> clone(); 復(fù)制一個(gè)連接梁丘,為了輪訓(xùn)和請(qǐng)求失敗的時(shí)候用
這里溫馨提示下:
Request request();
里面的返回值是okhttp3.Request侵浸。這里返回是okHttp的request。大家怎么看這個(gè)情況氛谜,我的理解是在接口層面指定了okHttp的request掏觉,則指明了底層的請(qǐng)求只能使用okHttp了
PS:大家注意一下這個(gè)接口和okhttp3.Call的接口基本上一致,只不過多了一個(gè)clone()方法值漫。
這個(gè)接口澳腹,目前就研究結(jié)束了,不知道大家怎么看待這個(gè)接口杨何,希望大家看完這個(gè)接口的介紹酱塔,心里對(duì)Call這個(gè)接口有一個(gè)比較深刻的認(rèn)識(shí)
三、CallAdapter接口
(一)危虱、思考
同樣兩個(gè)問題羊娃?
- 1、retrofit為什么要設(shè)計(jì)這個(gè)類?
- 2埃跷、如果讓我們?cè)O(shè)計(jì)蕊玷,我們?cè)趺丛O(shè)計(jì)這個(gè)接口
————————分割線,思考上面的問題——————————
不知道你們的想法捌蚊,不過我先說下我的想法
第一個(gè)問題 我是這么想的
我們知道retrofit是支持RxJava的集畅,那么如果一個(gè)RxJava是需要轉(zhuǎn)化成一個(gè)Retrofit中的Call<T>,那肯定需要一個(gè)適配器缅糟,把一個(gè)RxJava的Observable適配成一個(gè)Retrofit的Call<T>,所以設(shè)計(jì)這個(gè)類的主要目的就是適配讓Retrofit的Call<T>對(duì)業(yè)務(wù)層的請(qǐng)求適配祷愉,這樣整個(gè)結(jié)構(gòu)更清晰窗宦。
第二個(gè)問題 我是這樣想的
首先上面說了,既然是適配二鳄,肯定要有一個(gè)方法要去做適配把Retrofit的Call<T>適配成業(yè)務(wù)方自定義的"Call"赴涵。其次,大家知道Retrofit的Call<T>的泛型T是response的Body订讼,這個(gè)類型是泛型髓窜,所以最后反序列化的時(shí)候需要反序列化成一個(gè)對(duì)象,這個(gè)需要指定這個(gè)對(duì)象的類型欺殿,所以還應(yīng)該獲取這個(gè)類的具體"類型"寄纵。
這是我之前的想法,大家的想法如何脖苏?那我們來仔細(xì)看一下他的源代碼
(二)程拭、讀源碼
/**
* Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
* created by {@linkplain Factory a factory} which is
* {@linkplain Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit}
* instance.
*/
public interface CallAdapter<R, T> {
/**
* Returns the value type that this adapter uses when converting the HTTP response body to a Java
* object. For example, the response type for {@code Call<Repo>} is {@code Repo}. This type
* is used to prepare the {@code call} passed to {@code #adapt}.
* <p>
* Note: This is typically not the same type as the {@code returnType} provided to this call
* adapter's factory.
*/
Type responseType();
/**
* Returns an instance of {@code T} which delegates to {@code call}.
* <p>
* For example, given an instance for a hypothetical utility, {@code Async}, this instance would
* return a new {@code Async<R>} which invoked {@code call} when run.
* <pre><code>
* @Override
* public <R> Async<R> adapt(final Call<R> call) {
* return Async.create(new Callable<Response<R>>() {
* @Override
* public Response<R> call() throws Exception {
* return call.execute();
* }
* });
* }
* </code></pre>
*/
T adapt(Call<R> call);
/**
* Creates {@link CallAdapter} instances based on the return type of {@linkplain
* Retrofit#create(Class) the service interface} methods.
*/
abstract class Factory {
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*/
public abstract CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* Extract the raw class type from {@code type}. For example, the type representing
* {@code List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
1、老規(guī)矩先來看下 類 的注釋:
將一個(gè)Call和他的響應(yīng)類型R適配成T類型棍潘。實(shí)例由對(duì)應(yīng)的Factory來創(chuàng)建恃鞋,這個(gè)對(duì)應(yīng)的Factory是通過Retrofit.Builder的addCallAdapterFactory(Factory)方法添加到Retrofit對(duì)象中的崖媚,在上述的過程中實(shí)現(xiàn)的初始化。
再來看下他兩個(gè)方法的注釋
2恤浪、看下他的Type responseType()方法的注釋
返回此適配器將HTTP響應(yīng)body轉(zhuǎn)換為Java對(duì)象時(shí)使用的類型畅哑。 例如,"Call <Repo>"的響應(yīng)類型是"Repo"水由。 此類型用于準(zhǔn)備傳遞給"adapt"的"call"敢课。 注意:這通常與提供給此呼叫適配器工廠的"returnType"不同。
3绷杜、看下他的 T adapt(Call<R> call)方法的注釋
T 就是代表Retrofit里面Call的一個(gè)實(shí)例直秆。后面的我實(shí)在是翻譯不好,對(duì)不起大家了鞭盟,其實(shí)說白了就是講一個(gè)Retrofit的Call<T> 是適配成另外一個(gè)"Call"
4圾结、看下他的子類 abstract class Factory
看上面的源碼大家知道Factory是個(gè)子類,一般用Factory都是工廠模式齿诉。
老規(guī)矩看下他的 ***類**** 的注釋筝野,翻譯一下就是
基于Retrofit的create方法的返回值創(chuàng)建CallAdapter實(shí)例。
看完上面的注釋粤剧,大家應(yīng)該發(fā)現(xiàn)了Retrofit的一個(gè)規(guī)律就是:retrofit定義了CallAdapter接口歇竟,內(nèi)部有定義了一個(gè)Factory,工廠方法定義了如何生成CallAdapter抵恋,而CallAdapter又定義了如何拿到業(yè)務(wù)層定義的"Call"焕议。所以他們的順序如下:CallAdapter.Factory——>CallAdapter——>自定義的"Call"。
再來看下他的幾個(gè)方法
- public abstract CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) 的注釋:返回一個(gè)CallAdapter的實(shí)例弧关,如果工廠無法處理則返回null盅安。(注意:抽象的方法,需要子類去實(shí)現(xiàn)的)
- Type getParameterUpperBound(int index, ParameterizedType type) 注釋:
已知指定位置(index) 對(duì)應(yīng)的類型(type) 來獲取泛型中的通配符的參數(shù)的上線世囊,例如:Map <String别瞭,? 擴(kuò)展Runnable>株憾,則返回Runnable蝙寨。(靜態(tài)方法,有具體的實(shí)現(xiàn)) - static Class<?> getRawType(Type type) 注釋:提取type對(duì)應(yīng)的原始類型嗤瞎。例如:List<? extends Runnable> 則返回List.class
四墙歪、Callback接口
這個(gè)接口就比較簡單了,就不用大家思考了猫胁,Callback看字面意思就是回調(diào)箱亿,里面肯定一個(gè)是成功的回調(diào),一個(gè)是錯(cuò)誤的回調(diào)弃秆。直接讀下源碼
/**
* Communicates responses from a server or offline requests. One and only one method will be
* invoked in response to a given request.
* <p>
* Callback methods are executed using the {@link Retrofit} callback executor. When none is
* specified, the following defaults are used:
* <ul>
* <li>Android: Callbacks are executed on the application's main (UI) thread.</li>
* <li>JVM: Callbacks are executed on the background thread which performed the request.</li>
* </ul>
*
* @param <T> Successful response body type.
*/
public interface Callback<T> {
/**
* Invoked for a received HTTP response.
* <p>
* Note: An HTTP response may still indicate an application-level failure such as a 404 or 500.
* Call {@link Response#isSuccessful()} to determine if the response indicates success.
*/
void onResponse(Call<T> call, Response<T> response);
/**
* Invoked when a network exception occurred talking to the server or when an unexpected
* exception occurred creating the request or processing the response.
*/
void onFailure(Call<T> call, Throwable t);
1届惋、先看下 類 的注釋
從服務(wù)器或離線請(qǐng)求的對(duì)應(yīng)的響應(yīng)(response)髓帽。 對(duì)應(yīng)指定請(qǐng)求的,有且僅有一個(gè)方法與其對(duì)應(yīng)脑豹。
由Retrofit的callback executor執(zhí)行回調(diào)方法郑藏。當(dāng)沒有指定時(shí),使用下面的默認(rèn)值:
如果是 Android:回調(diào)在應(yīng)用程序的主(UI)線程上執(zhí)行瘩欺,如果是JVM必盖,則在執(zhí)行請(qǐng)求的后臺(tái)線程上執(zhí)行回調(diào)。
泛型參數(shù)<T> 代表成功的響應(yīng)類的類型
這個(gè)接口就兩個(gè)方法俱饿,一個(gè)對(duì)應(yīng)成功的回調(diào)歌粥,一個(gè)對(duì)應(yīng)失敗的回調(diào)
- 1、void onResponse(Call<T> call, Response<T> response) 注釋:調(diào)用接收的HTTP響應(yīng)拍埠。注意:HTTP響應(yīng)可能是指示應(yīng)用程序級(jí)別的故障失驶,例如404或500。調(diào)用 Response的isSuccessful()方法來判斷響應(yīng)是否成功枣购。
- 2嬉探、void onFailure(Call<T> call, Throwable t) :注釋:當(dāng)與服務(wù)器交互時(shí)、當(dāng)創(chuàng)建請(qǐng)求棉圈、當(dāng)處理響應(yīng)時(shí)產(chǎn)生Exception 均調(diào)動(dòng)該方法涩堤。
五、Converter接口
Converter我認(rèn)為挺簡單的分瘾,就是負(fù)責(zé)類型轉(zhuǎn)換
(一)胎围、思考
一個(gè)問題:
1、如果讓你"設(shè)計(jì)"這個(gè)Converter接口你要怎么設(shè)計(jì)
————————分割線芹敌,思考上面的問題——————————
這個(gè)問題 我是這么想的
因?yàn)槭墙o網(wǎng)絡(luò)場景下的使用的痊远,我的第一反應(yīng)是寫兩個(gè)方法,一個(gè)方法是在請(qǐng)求的時(shí)候氏捞,寫數(shù)據(jù)進(jìn)行序列化的時(shí)候;還有一個(gè)就是在響應(yīng)的時(shí)候, 讀取數(shù)據(jù)進(jìn)行反序列化的時(shí)候冒版。
(二)液茎、源碼
/**
* Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
* Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
* into the {@link Retrofit} instance.
*/
public interface Converter<F, T> {
T convert(F value) throws IOException;
/** Creates {@link Converter} instances based on a type and target usage. */
abstract class Factory {
/**
* Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for
* response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
* declaration.
*/
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
* values.
*/
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Field @Field}, {@link FieldMap @FieldMap} values,
* {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
* {@link Query @Query}, and {@link QueryMap @QueryMap} values.
*/
public Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
}
}
1、看下類的注釋
在HTTP請(qǐng)求中實(shí)現(xiàn)對(duì)象的轉(zhuǎn)化辞嗡。Converter這個(gè)類的實(shí)例由Factory創(chuàng)建捆等。而這個(gè)Factory則由Retrofit.Builder的addConverterFactory()方法來進(jìn)行初始化的
這個(gè)接口的抽象方法比較少,就一個(gè)
T convert(F value) throws IOException
不用注釋续室,大家也知道把F 轉(zhuǎn)化為T栋烤,這個(gè)接口是有兩個(gè)參數(shù)的,我把F稱為轉(zhuǎn)入類型,T為轉(zhuǎn)出類型挺狰,因?yàn)橐袴轉(zhuǎn)化為T明郭。
哎 好像和我想象的不一樣哎买窟,那我們繼續(xù)看下他的抽象類Factory
2、抽象類Factory
看名字就知道是個(gè)工廠類薯定,肯定是通過這個(gè)工廠來產(chǎn)生Converter對(duì)象始绍。
(1)、看下類的注釋
基于類型和目標(biāo)來創(chuàng)建一個(gè)Converter的實(shí)例
(2)话侄、看下對(duì)應(yīng)的三個(gè)方法的注釋
- 1亏推、public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) 注釋:返回一個(gè)處理HTTP 響應(yīng)的的body的Converter(轉(zhuǎn)換器)年堆,轉(zhuǎn)入類型ResponseBody吞杭,如果因?yàn)閠ype(類型)無法處理,工廠無法處理,則返回null变丧。例如:一個(gè)Retrofit的Call是Call<SimpleResponse>芽狗,則對(duì)應(yīng)的響應(yīng)body的類型應(yīng)該是 SimpleResponse。
- 2锄贷、Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) 注釋:返回一個(gè)可以處理將HTTP的請(qǐng)求(resquest)中的body的Converter對(duì)象译蒂,轉(zhuǎn)出類型是RequestBody。如果因?yàn)閠ype(類型)無法處理谊却,則返回null柔昼。這個(gè)Converter主要是為了處理@Body 注解,@Part 注解炎辨,@PartMap的類型轉(zhuǎn)換捕透。
- 3、Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) 注釋:支持返回一個(gè)轉(zhuǎn)出類型為String的Converter實(shí)例碴萧。如果類型不能處理乙嘀,則返回null。這個(gè)主要是為了 @Field破喻,F(xiàn)ieldMap虎谢,@FieldMap , @Header, @HeaderMap曹质, @Path婴噩, @Query, @QueryMap 這些注解創(chuàng)建的 @Converter轉(zhuǎn)換器
(3)羽德、總結(jié)
Retrofit 明顯想的比我多几莽,設(shè)計(jì)比我優(yōu)雅,那我們來總結(jié)下這個(gè)接口
- 1宅静、Converter 這個(gè)類的職責(zé)主要是做** 類型轉(zhuǎn)化 **章蚣,Retrofit定義了Converter,但是接口內(nèi)部有個(gè)內(nèi)部類負(fù)責(zé)創(chuàng)建Converter姨夹。
- 2纤垂、大家注意到?jīng)]Factory雖然是個(gè)抽象類矾策,但是他的三個(gè)方法都不是抽象方法洒忧。
- 3蝴韭、Factory的三個(gè)方法目的不一樣蛉抓,都的是真針對(duì)請(qǐng)求體,有的針對(duì)響應(yīng)體飞蹂。
六几苍、ExecutorCallAdapterFactory
上文講解Platform中的靜態(tài)內(nèi)部類Android的defaultCallAdapterFactory方法里面返回的是一個(gè)ExecutorCallAdapterFactory的對(duì)象。那我們就在講解下ExecutorCallAdapterFactory類
(一)陈哑、上源碼
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
// get方法妻坝,創(chuàng)建并返回Android平臺(tái)默認(rèn)CallAdapter
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//先判斷原始類型是不是Call,這個(gè)Call是retrofit包下的Call
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}
麻蛋惊窖,又是一個(gè)沒有注釋的類刽宪,不過通過源碼我們知道這是一個(gè)final類,不能被繼承界酒。
首先這個(gè)ExecutorCallAdapterFactory類實(shí)現(xiàn)了CallAdapter.Factory圣拄,所以必然實(shí)現(xiàn)了CallAdapter.Factory接口的方法,我們來看下這個(gè)get方法內(nèi)部的實(shí)現(xiàn)流程
- 1毁欣、首先判斷原始類型
- 2售担、通過調(diào)用Utils.getCallResponseType()獲取** "響應(yīng)" **(不是"相應(yīng)")的類型。
- 3署辉、new了一個(gè)CallAdapter的匿名內(nèi)部類,注意這個(gè)CallAdapter的兩個(gè)泛型分別是Object和Call<?>岩四,這個(gè)CallAdapter的兩個(gè)抽象方法的實(shí)現(xiàn):(1)哭尝、Type responseType返回的是第2步產(chǎn)生的"響應(yīng)"類型;(2)蹦锋、Call<Object> adapt(Call<Object> call) 方法返回的是 new的一個(gè)ExecutorCallbackCall對(duì)象妹蔽。
ExecutorCallbackCall是個(gè)神馬東西赋访,原來ExecutorCallbackCall是ExecutorCallAdapterFactory的靜態(tài)內(nèi)部類律罢,那么我們來分析一下ExecutorCallAdapterFactory類。
(二)桶唐、ExecutorCallbackCall類分析
1栅葡、上源碼
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
2、看上面源碼我們能得知如下內(nèi)容:
- 1尤泽、ExecutorCallbackCall實(shí)現(xiàn)了Retrofit里面的Call接口欣簇,所以ExecutorCallbackCall是Retrofit里面的Call的實(shí)現(xiàn)類,所以必然實(shí)現(xiàn)了對(duì)應(yīng)Call的抽象類坯约。
- 2熊咽、如果想要構(gòu)造一個(gè)ExecutorCallbackCall對(duì)象,必須傳入一個(gè)Executor和Call兩個(gè)對(duì)象才行闹丐。
- 3横殴、無論是發(fā)起同步請(qǐng)求還是異步請(qǐng)求,或者取消請(qǐng)求卿拴,其實(shí)真正的操作對(duì)象是衫仑,構(gòu)造時(shí)傳入的delegate。
- 4堕花、無論同步文狱,還是異步,調(diào)用的線程池都是 航徙,構(gòu)造時(shí)傳入的callbackExecutor如贷,而在Android那部分我們知道callbackExecutor其實(shí)就是MainThreadExecutor,所以最后無論同步還是異步到踏,最后都會(huì)切換到UI主線程中去
3杠袱、所以總結(jié)一下ExecutorCallbackCall類
它實(shí)現(xiàn)了Call這個(gè)接口,Call我們前面說了窝稿,就是一個(gè)網(wǎng)絡(luò)請(qǐng)求楣富,然而我們這里看到這里并沒有做實(shí)際請(qǐng)求,而是用了一個(gè)靜態(tài)代理伴榔,通過這個(gè)delegate代理來實(shí)現(xiàn)call的請(qǐng)求纹蝴,而在這里面做了一些其他的邏輯比如cancel邏輯,而實(shí)際上做這個(gè)請(qǐng)求還是交給了delegate踪少。(其實(shí)OkHttpCall)
(三) ExecutorCallAdapterFactory 類總結(jié)
ExecutorCallAdapterFactory是CallAdapter.Factory的實(shí)現(xiàn)類塘安,ExecutorCallAdapterFactory是將Call 適配成Call接口。但適配前和適配后的Call 還是不一樣的援奢,從enqueue方法中可以看到在callbackExecutor執(zhí)行了回調(diào)兼犯,callbackExecutor上文已經(jīng)介紹了,在Android平臺(tái)就是UI主線程切黔。
七砸脊、Platform類
為了方便大家后期更好的理解源碼,我先給大家介紹一下Platform纬霞。這個(gè)Platform是個(gè)神馬東東凌埂,字面理解是"平臺(tái)",有啥神功療效诗芜?
工欲善其事必先利其器瞳抓,我們先來看下源碼
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
Executor defaultCallbackExecutor() {
return null;
}
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
boolean isDefaultMethod(Method method) {
return false;
}
Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args)
throws Throwable {
throw new UnsupportedOperationException();
}
@IgnoreJRERequirement // Only classloaded and used on Java 8.
static class Java8 extends Platform {
@Override boolean isDefaultMethod(Method method) {
return method.isDefault();
}
@Override Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
Object... args) throws Throwable {
// Because the service interface might not be public, we need to use a MethodHandle lookup
// that ignores the visibility of the declaringClass.
Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);
return constructor.newInstance(declaringClass, -1 /* trusted */)
.unreflectSpecial(method, declaringClass)
.bindTo(object)
.invokeWithArguments(args);
}
}
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
}
這個(gè)類好坑啊,居然沒有注釋绢陌,不過通知字面的意思挨下,我們
(一)、初始化
Platform 的初始化
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
Platform字面的意思就是平臺(tái)脐湾。所以Platform其實(shí)就是一個(gè)父類臭笆,不同平臺(tái)對(duì)應(yīng)不同的實(shí)現(xiàn)子類。Android秤掌、Java 8 對(duì)應(yīng)的是各種具體平臺(tái)愁铺。可以看到闻鉴,調(diào)用findPlatform()方法之后就回去判斷對(duì)應(yīng)的平臺(tái)茵乱,具體實(shí)現(xiàn)的子類就是Android 和Java。
這里提一下我的小插曲孟岛,按照我之前分析okHttp的思路瓶竭,okHttp里面也有Platform。所以我直接在Retrofit的包下找AndroidPlatform渠羞,結(jié)果發(fā)現(xiàn)沒有斤贰,我就蒙圈了,后來才發(fā)現(xiàn)在Platform的內(nèi)部類里面次询,汗.....
由于我們針對(duì)Android平臺(tái)關(guān)于Java的具體設(shè)置荧恍,我就不講解了,這里看下對(duì)應(yīng)的Platform的內(nèi)部類Anroid
(二)屯吊、Android
Android是Platform的靜態(tài)內(nèi)部類
代碼很簡介送巡,如下:
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
}
而Android類就兩個(gè)方法,一個(gè)是defaultCallbackExecutor盒卸,另外一個(gè)是defaultCallAdapterFactory骗爆,從字面的意思我們可以知道,defaultCallbackExecutor()這個(gè)方法應(yīng)該是返回的是默認(rèn)的回調(diào)的線程池容器蔽介,defaultCallAdapterFactory()方法返回的是默認(rèn)的請(qǐng)求適配工廠(CallAdapterFactory)淮腾。
那MainThreadExecutor是什么東西糟需?原來MainThreadExecutor是Android的靜態(tài)內(nèi)部類。那我們來看下MainThreadExecutor這個(gè)類
(三)谷朝、MainThreadExecutor
看字面意思,我的理解是主線程的線程池武花。
來看下源碼:
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
代碼很簡單圆凰,通過new Handler(Looper.getMainLooper())來獲取一個(gè)主線程的Handler。然后在執(zhí)行主線程的時(shí)候体箕,調(diào)用的是主線程的handler的post方法专钉。
ExecutorCallAdapterFactory 這個(gè)類 我們?cè)谙旅嬷v解。
(四)累铅、總結(jié)
Platform 其實(shí)就是一個(gè)"平臺(tái)",定義了一些平臺(tái)共有的方法跃须,然后也針對(duì)不同的平臺(tái)定義了一些不同的具體實(shí)現(xiàn)子類,比如各個(gè)不同平臺(tái)根據(jù)不同環(huán)境來初始化不同的MainThreadExecutor娃兽。這里也可以看到菇民,在初始化Platform之后,通過Platform得到的ExecutorCallAdapterFactory的工廠的Excecutor其實(shí)就是運(yùn)行在主線程的Executor投储。
八 HttpException類
這個(gè)類比較簡單第练,就不用想了,肯定肯定是Retrofit處理異常的的異常包裝類玛荞,代碼不多娇掏,直接上源碼:
/** Exception for an unexpected, non-2xx HTTP response. */
public class HttpException extends Exception {
private static String getMessage(Response<?> response) {
if (response == null) throw new NullPointerException("response == null");
return "HTTP " + response.code() + " " + response.message();
}
private final int code;
private final String message;
private final transient Response<?> response;
public HttpException(Response<?> response) {
super(getMessage(response));
this.code = response.code();
this.message = response.message();
this.response = response;
}
/** HTTP status code. */
public int code() {
return code;
}
/** HTTP status message. */
public String message() {
return message;
}
/**
* The full HTTP response. This may be null if the exception was serialized.
*/
public Response<?> response() {
return response;
}
}
通過注釋我們知道,這個(gè)HttpException主要是用來處理意外的勋眯、非2xx的響應(yīng)異常
這個(gè)類就三個(gè)變量
- int code :http的狀態(tài)code婴梧,比如:405、501等
- String message : http狀態(tài)的信息
- Response<?> response : 服務(wù)器的響應(yīng)
這個(gè)三個(gè)參數(shù)在構(gòu)造函數(shù)里面進(jìn)行初始化的客蹋,由于這三個(gè)變量分別是private塞蹭,所以必然有一個(gè)對(duì)應(yīng)的get方法。不過這里的方法并沒有以"get"開頭嚼酝。
最后他又定義了 靜態(tài)方法getMessage(Response<?>)浮还,傳入一個(gè)Response,返回一個(gè)拼接的String。
PS:
HttpException 里面的Response是Retrofit里面的Response闽巩,OkHttp里面也有一個(gè)Response钧舌。大家不要混淆了!
這個(gè)類比較簡單涎跨,只能講這么多了
九洼冻、面向接口編程
面向接口編程
Interface-based programming, also known as interface-based architecture, is an architectural pattern for implementing modular programming at the component level in an object-oriented programming language which does not have a module system.
翻譯一下:
面向接口編程,也被熟知為基于接口的設(shè)計(jì)隅很,是一種基于組件級(jí)別的撞牢,面向?qū)ο笳Z言的模塊化編程設(shè)計(jì)實(shí)現(xiàn)。
說道面向接口不得不說面向?qū)ο螅贿^面向接口編程和面向?qū)ο缶幊虒?shí)際上兩個(gè)不同層級(jí)的概念屋彪。理論上說具有對(duì)象概念的程序設(shè)計(jì)都可以稱之為面向?qū)ο缶幊趟祝嫦蚪涌诰幊虅t是從組件的級(jí)別來設(shè)計(jì)代碼,認(rèn)為地將抽象與實(shí)現(xiàn)分離畜挥。面向接口編程僅僅是面向?qū)ο缶幊痰囊环N模塊化實(shí)現(xiàn)形式而已仔粥。
(一)所謂的“接口”
面向接口編程中的"接口" 二字具體到Java語言中不僅僅是"interface"關(guān)鍵字這么簡單⌒返可以理解為接口是對(duì)具體實(shí)現(xiàn)的抽象躯泰。試想一下,團(tuán)隊(duì)協(xié)同以及代碼健壯可維護(hù)性的需求日益增強(qiáng)的趨勢(shì)下华糖,通過暴露接口來提供服務(wù)本身是一件非常愉悅的事情麦向。A需要調(diào)用B的服務(wù),A卻不需要去仔細(xì)閱讀B寫的代碼客叉,通過接口文檔就可以看出對(duì)應(yīng)業(yè)務(wù)的方法和參數(shù)類型诵竭,進(jìn)而使用RMI或者RPC等相關(guān)技術(shù)實(shí)現(xiàn)模塊化的調(diào)用。而這一切本身就是相面接口編程十办。
換一種角度秀撇,我們?cè)趺炊x接口:“接口泛指實(shí)體把自己提供給外界的一種抽象化物,用以由內(nèi)部操作分離出外部溝通方法向族,使其能被修改內(nèi)部而不影響外界其他實(shí)體與其交互的方式”呵燕,話句話說,在我們程序的世界里件相,接口的作用就是用于定義一個(gè)或一組規(guī)則再扭,實(shí)現(xiàn)對(duì)應(yīng)接口的實(shí)體需要遵循對(duì)應(yīng)的這些規(guī)則。也可以說是對(duì)“同類事物”的抽象表示夜矗,而“同類事物”的界定就看是否實(shí)現(xiàn)了同一個(gè)接口泛范,譬如一個(gè)Animal接口和NightWorking接口,公雞實(shí)現(xiàn)了Animal接口紊撕,貓頭鷹實(shí)現(xiàn)了Animal接口和NightWorking接口罢荡,還有一個(gè)實(shí)現(xiàn)了NightWorking的接口的酒吧,在Animal的范疇下对扶,我們可以稱公雞和貓頭鷹是同類事物区赵,但是在NightWorking的范疇下,我們可以把我們可以稱貓頭鷹和酒吧是同類事物浪南。有點(diǎn)恐怖吧
很多剛剛接觸面向接口編程的Java開發(fā)者會(huì)認(rèn)為笼才,既然面向接口編程,那么就把實(shí)現(xiàn)抽象為接口就是優(yōu)良的設(shè)計(jì)络凿。但實(shí)際上他們混淆了Java中的interface和面向接口編程的"接口的"概念骡送。實(shí)際上昂羡,interface、abstract class以及普通的class 都能成為所謂的接口摔踱,甚至 abstract class的功能可以更加強(qiáng)大虐先。那么interface和abstract class 區(qū)別是什么?
(二)昌渤、abstract class和interface的區(qū)別:
abstract class和interface的區(qū)別在于赴穗,interface約定的是務(wù)必實(shí)現(xiàn)的方法,強(qiáng)調(diào)的是規(guī)則的制定膀息。abstract class則是在抽象的同時(shí)允許提供一些默認(rèn)的行為,以達(dá)到代碼復(fù)用的效果了赵。例如一定一些基礎(chǔ)潜支、初始化以及類回收方法等。另外柿汛,還有一個(gè)常識(shí)性的區(qū)別冗酿,一個(gè)實(shí)現(xiàn)類(相對(duì)于抽象而言)可以實(shí)現(xiàn)多個(gè)interface,而只能繼承一個(gè)abstract class络断,在代碼設(shè)計(jì)的過程中務(wù)必注意裁替。
(三)、面向接口的優(yōu)勢(shì):
- 1貌笨、方便程序使用多態(tài)
例如有方法需要一個(gè)集合類型的參數(shù)弱判,將參數(shù)設(shè)置為List類型和設(shè)置成ArrayList相比,入慘不僅可以傳入ArrayList類型還可以是LinkedList類型锥惋,因此代碼使用范圍更廣昌腰。 - 2、代碼擴(kuò)展性更強(qiáng)
如果要擴(kuò)展一個(gè)類的方法膀跌,我們一般可以選擇動(dòng)態(tài)代理方式來對(duì)某些方法進(jìn)行增強(qiáng)遭商,但是動(dòng)態(tài)代理的類需要實(shí)現(xiàn)接口,這也是面試接口編程的一大優(yōu)勢(shì)捅伤。 - 3劫流、降低了代碼間的耦合
例如:計(jì)算機(jī)Computer類有一個(gè)IStrorage接口類型和成員變量,接口定義了write和read方法丛忆,移動(dòng)設(shè)備類FlashDisk祠汇,MP3類實(shí)現(xiàn)了IStrorage接口,那么計(jì)算Computer類和FlashDisk蘸际、MP3就能關(guān)聯(lián)成功座哩,但是Computer并不知道自己的成員變量是什么具體類型,這就是所有的"依賴幾口粮彤,而不依賴具體類"根穷。Java中兩個(gè)層面之間通過接口產(chǎn)生聯(lián)系姜骡,此時(shí)接口相當(dāng)于一個(gè)緩沖區(qū),當(dāng)業(yè)務(wù)發(fā)生改變屿良,只改變實(shí)現(xiàn)類的代碼即可圈澈,必須要改寫后續(xù)代碼,減少對(duì)整個(gè)系統(tǒng)的影響尘惧。
(四)康栈、 面向接口的編程方式
- "定義接口"——"定義類": 先定義接口,再實(shí)現(xiàn)類
- 任何需要在函數(shù)間傳入傳出的一定是接口而不是具體的類喷橙,面向接口的編程方式是Java成功關(guān)鍵之一啥么,因?yàn)檫m合多人同時(shí)開發(fā)。
- 一方只認(rèn)識(shí)接口贰逾,想進(jìn)入另一方悬荣,就披上那個(gè)接口外套吧。