android中Retrofit源碼解析(新版)
在android開發(fā)中我們原生應(yīng)用發(fā)起網(wǎng)絡(luò)請求的時(shí)候杯拐,不免需要使用android對網(wǎng)絡(luò)請求的封裝,它提供了對http協(xié)議底層的抽象错森,我們可以通過它提供的方法直接調(diào)用http請求。在android2.2版本及其以前的版本使用HttpClient,在android2.3版本及其之后我們使用了httpUrlConnection翘瓮,而且在6.0之后android移除了httpClient箱舞,我們在高版本的API中只能使用HttpUrlConnection了遍坟。
1.1 retrofit和OkHttp的關(guān)系
但是實(shí)際情況是使用了httpUrlConnection還是很繁瑣,我們還是要去考慮超時(shí)時(shí)間晴股,服務(wù)器異常情況愿伴、數(shù)據(jù)流轉(zhuǎn)為實(shí)體對象這些煩惱。所以有了對android內(nèi)置的HttpUrlConnection or httpClient的包裝电湘,讓我們專心處理業(yè)務(wù)邏輯隔节。oKHttp就誕生了,android4.4版本以后都內(nèi)置了oKHttp了寂呛,而我們要討論的retrofit就是再次對okHttp的包裝怎诫,豐富了很多強(qiáng)大的功能,比如能和Rxjava這個(gè)流行的框架結(jié)合贷痪,返回結(jié)果能回調(diào)到UI線程等幻妓。oKHttp的源碼涉及到了對阻塞隊(duì)列,線程池的應(yīng)用呢诬,我們下一節(jié)進(jìn)行探討涌哲。
1.2 retrofit的本質(zhì)
retrofit的本質(zhì)就是應(yīng)用了大量的設(shè)計(jì)模式對Okhttp進(jìn)行了封裝,加入了網(wǎng)絡(luò)數(shù)據(jù)轉(zhuǎn)換尚镰、網(wǎng)絡(luò)請求回調(diào)阀圾、網(wǎng)絡(luò)請求適配這幾個(gè)主要的功能。它本身肯定不會去發(fā)請求的狗唉,發(fā)請求交給了OkHttp初烘,它只對調(diào)用方式和返回結(jié)果進(jìn)行處理其他的不關(guān)它的事。為什么要去研究retrofit的源碼呢分俯?因?yàn)樗庋b的方式解耦性很高肾筐,功能調(diào)用十分簡潔,可以參照它對我們的代碼也能進(jìn)行改造缸剪。
1.3 源碼解析(retrofit:2.4.0)
1.3.1 retrofit的創(chuàng)建
一起打開IDE閱讀源碼更虛嘎痤怼!retrofit的創(chuàng)建是整個(gè)框架的入口杏节,它肯定會提前準(zhǔn)備好很多看不懂的變量進(jìn)行初始化唬渗,但是這不能阻擋我們典阵,往后看就能理解它代表的含義了。根據(jù)官方的文檔镊逝,retrofit的創(chuàng)建使用了建造者模式壮啊。
Retrofit retrofit = new Retrofit.Builder()
//基本URL
.baseUrl("https://www.baidu.com")
//網(wǎng)絡(luò)請求適配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//網(wǎng)絡(luò)請求數(shù)據(jù)轉(zhuǎn)換器
.addConverterFactory(GsonConverterFactory.create())
//網(wǎng)絡(luò)請求執(zhí)行器
.client(new OkHttpClient())
.build();
所謂建造者模式就是有builder關(guān)鍵字的方式,就是這么簡單撑蒜!當(dāng)然這是一個(gè)玩喜歹啼,建造者模式和我們以前 get/set 類的屬性沒有什么本質(zhì)的區(qū)別,主要是將這些set方法全部提取出來 形成一個(gè)抽象類或者內(nèi)部類座菠,然后在一個(gè)建造者類里面去設(shè)置屬性狸眼,返回一個(gè)實(shí)體類對象,列如:
public abstract Builder{
public void BulidProperty(String url);
}
public class RealBuilder extends Builder{
private RealObject object;
public void BulidProperty(String url){
object.SetProperty(url);
}
public RealObject build(){
return RealObject;
}
}
簡單的思想大概是這樣的辈灼,具體的我們可以看一下Retrofit中的源碼份企。第一行代碼
//第一行代碼
Retrofit retrofit = new Retrofit.Builder()
很明顯這個(gè)Builder是一個(gè)Retrofit的內(nèi)部類,那說明建造者不是繼承了抽象類巡莹,而是使用了內(nèi)部類來設(shè)置屬性司志。來看一下這個(gè)內(nèi)部類,如下:
public static final class Builder {
//不知道這是什么東東先放在一邊
private final Platform platform;
//很明顯出現(xiàn)了okhttp降宅,就知道它肯定負(fù)責(zé)去發(fā)請求
private okhttp3.Call.Factory callFactory;
// 8必多說 大家都懂
private HttpUrl baseUrl;
//很明顯它是存數(shù)據(jù)轉(zhuǎn)換用的骂远,但是為什么搞一個(gè)list 懵b?
private final List<Converter.Factory> converterFactories = new ArrayList<>();
//很明顯它存網(wǎng)絡(luò)適配器用的腰根,再次疑問這個(gè)網(wǎng)絡(luò)適配器是什么東東激才?
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
//很明顯他是一個(gè)回調(diào)執(zhí)行器,這個(gè)有什么用呢额嘿?
private Executor callbackExecutor;
//這肯定是校驗(yàn)Flag目前不知道有什么用
private boolean validateEagerly;
里面看不懂的變量主要有adapterFactories存的網(wǎng)絡(luò)適配器工廠(CallAdapter.Factory)瘸恼,很明顯他后面會使用工廠設(shè)計(jì)模式去產(chǎn)生CallAdapter的對象祠肥,至于數(shù)據(jù)轉(zhuǎn)換器(converter)我們都知道http請求返回來的是數(shù)據(jù)流InputStream方式的时捌,轉(zhuǎn)為Json,XML之類需要一個(gè)轉(zhuǎn)換器巩踏,類似于一個(gè)double轉(zhuǎn)int的工具類球拦。
- 網(wǎng)絡(luò)適配器的含義及其作用:網(wǎng)絡(luò)適配器是我自己給他的定義靠闭,從命名上來看是叫:CallAdapter,Call肯定是來發(fā)請求的坎炼,Adapter憶往昔崢嶸歲月愧膀,在listView里面是界面和數(shù)據(jù)的橋梁,同理這里的CallAdapter應(yīng)該是客戶端和網(wǎng)絡(luò)之間橋梁谣光¢萘埽客戶端發(fā)請求的操作肯定是要通過它的。如圖:
這樣我們就可以清楚的看到了CallAdapter的作用了萄金,它對OkHttp進(jìn)行包裝狼钮,我們調(diào)用請求方法的時(shí)候都要通過它碳柱。它同時(shí)持有了okHttp對象和回調(diào)執(zhí)行器的對象,這樣它通過Okhttp拿到數(shù)據(jù)之后熬芜,用回調(diào)執(zhí)行器回調(diào)。
- 回調(diào)執(zhí)行器:回調(diào)執(zhí)行器就是在拿到數(shù)據(jù)結(jié)果之后福稳,我們怎么返回結(jié)果的問題涎拉,主要的問題就是由于是異步請求,我們想要使用數(shù)據(jù)填充界面的圆,需要切換到主線程鼓拧。
//再看看構(gòu)造函數(shù)
Retrofit retrofit = new Retrofit.Builder()
這個(gè)內(nèi)部類的構(gòu)造函數(shù)做了些什么內(nèi)容?就一句調(diào)用自己的有參構(gòu)造函數(shù)越妈,佛了季俩!
public Builder() { this(Platform.get());}
我們來看看這個(gè)有參構(gòu)造函數(shù)和Platform類是什么東東:
//Platform類
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
//f返回一個(gè)實(shí)例就完事了
return PLATFORM;
}
//根據(jù)不同運(yùn)行平臺返回對應(yīng)的Platforem對象
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();
}
看到這里我們就明白了,他根據(jù)運(yùn)行的平臺不同來返回相應(yīng)的對象梅掠,我們這里只分析 new Adnroid();看看里面有什么內(nèi)容:
static class Android extends Platform {
//一個(gè)默認(rèn)的回調(diào)執(zhí)行器
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
//很明顯 很熟悉 酌住!創(chuàng)建了一個(gè)默認(rèn)的CallAdapter(網(wǎng)絡(luò)適配器),而且傳入了一個(gè)回調(diào)執(zhí)行器(回調(diào)執(zhí)行器可以自定義阎抒,不然就是用默認(rèn)綁定主線程)
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
//給力 綁定了主線程的 looper (關(guān)于Handler的詳細(xì)內(nèi)容可以自己查詢)
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
到此我們明白了 Platfrom的作用了酪我,它提供了一個(gè)默認(rèn)的CallAdapter.Factory用來生產(chǎn)CallAdapter,還提供了一個(gè)綁定主線程的默認(rèn)回調(diào)執(zhí)行器且叁。
再次回頭看創(chuàng)建Retrofit的其他代碼
Retrofit retrofit = new Retrofit.Builder()
//基本URL
.baseUrl("https://www.baidu.com")
//可以自定義回調(diào)執(zhí)行器都哭,否則默認(rèn)回調(diào)到主線程
.callbackExecutor("xxxx")
//網(wǎng)絡(luò)請求適配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//網(wǎng)絡(luò)請求數(shù)據(jù)轉(zhuǎn)換器
.addConverterFactory(GsonConverterFactory.create())
//網(wǎng)絡(luò)請求執(zhí)行器
.client(new OkHttpClient())
.build();
baseUrl、add這些方法是給內(nèi)部類屬性賦值逞带,我們主要來看build()方法欺矫。
public Retrofit build() {
//可見baseUrl 是必須的 使用的時(shí)候要注意
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//很明顯 生產(chǎn)網(wǎng)絡(luò)請求的工廠,如果你不傳入自定義的okHttp對象展氓,他會默認(rèn)使用okHttpclient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//如果沒有自定義穆趴,加入剛剛說過的默認(rèn)調(diào)到到主線程
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//將傳入到內(nèi)部類callAdapter copy一份 傳入到retrofit的構(gòu)造函數(shù)
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//它會添加一個(gè)默認(rèn)的網(wǎng)絡(luò)適配器,這個(gè)網(wǎng)絡(luò)適配器它持有callbackExecutor回調(diào)執(zhí)行器的對象带饱。
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//很明顯類似adapterFactories 添加了一個(gè)默認(rèn)毡代,再copy一份到 retrofit的構(gòu)造函數(shù)中。
List<Converter.Factory> converterFactories =new ArrayList<>(1 + this.converterFactories.size());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//返回retrofit的實(shí)例對象就完事了
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
這里的代碼都很簡單勺疼,但是有幾個(gè)疑問教寂?為什么這個(gè)adapterFactories和converterFactories都是list呢,它里面都存了些什么执庐。
- adapterFactories: 一個(gè)list集合酪耕,存儲了網(wǎng)絡(luò)適配器工廠,根據(jù)上面的代碼我們可以看到它里面的內(nèi)容是:先添加了自定義的轨淌、后面添加了一個(gè)默認(rèn)的迂烁,總共兩個(gè)元素看尼。在Retrofit中提供了四種CallAdapterFactory: ExecutorCallAdapterFactory(默認(rèn))、GuavaCallAdapterFactory盟步、Java8CallAdapterFactory藏斩、RxJavaCallAdapterFactory。其他的沒有用過却盘,但是看到Rxjava我們就知道了狰域,如果想要和Rxjava結(jié)合起來這個(gè)RxJavaCallAdapterFactory必須添加進(jìn)去
//通過這個(gè)添加進(jìn)去,是不是可以添加多個(gè)呢黄橘?
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//我們還可以添加
// adapterFactories里面順序
// 自定義1-自定義2-.....默認(rèn)兆览。
addCallAdapterFactory(Java8CallAdapterFactory.create())
addCallAdapterFactory(GuavaCallAdapterFactory.create())
//converter 同理啊鐵子!
.addConverterFactory(GsonConverterFactory.create())
也不會有問題塞关,因?yàn)槲覀兙W(wǎng)絡(luò)請求都是多種多樣的抬探,上面已經(jīng)說得我們發(fā)請求就是操作CallAdapter,所以有結(jié)果返回的時(shí)候也需要通過CallAdapter帆赢。有時(shí)候我們需要Rxjava的observeable這種返回對象小压,有時(shí)候我們還是需要Call這種類型的返回對象,所以他需要一個(gè)list去組裝對應(yīng)的CalladapterFactory匿醒,Call代表了默認(rèn)CallAapter返回出來的的场航,Observable代表了我們添加進(jìn)去的RxJavaCallAdapter返回出來的。同理我們需要從CallAdapter得到想要的數(shù)據(jù)類型廉羔,converterFactories也需要多個(gè)溉痢。
@GET
//我想要Observable 需要相應(yīng)的的CallAdapter
Observable<ResponseBody> download(@Url String url);
@GET
//我想要Call 默認(rèn)的CallAdapter就行
//同時(shí)還需要將結(jié)果變成IModel 怎么說吧你
Call<IModel>download(@Url String url);
總結(jié):我們清楚的看到了,retrofit的創(chuàng)建過程憋他,主要的內(nèi)容就是四個(gè)器的初始化孩饼,網(wǎng)絡(luò)適配器(CallAdapter),數(shù)據(jù)轉(zhuǎn)換器(conver)竹挡,請求執(zhí)行器(oKHttp)镀娶,回調(diào)執(zhí)行器(callbackExecutor)。關(guān)注點(diǎn)在我們發(fā)請求操作都是CallAdapter揪罕,它肯定持有其他三個(gè)的引用梯码,就像吃雞里面他是我們的角色,其他的是M4,頭盔 藥品等好啰。
1.3.2 創(chuàng)建網(wǎng)絡(luò)請求接口的實(shí)例轩娶。
對我們的的注解定義的接口方法進(jìn)行解析,從而創(chuàng)建實(shí)例框往,有點(diǎn)迷惑鳄抒?什么實(shí)例,干什么用的?我們繼續(xù)往下看许溅。
retrofit.create(RetrofitService.class);
看到這種傳入.class的 瓤鼻,我們可以想到肯定會用到反射。
public <T> T create(final Class<T> service) {
//校驗(yàn)接口正確性贤重,是否符合注解規(guī)則
Utils.validateServiceInterface(service);
//validateEagerly 這個(gè)變量主要是作用是 是否提前加入緩存
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//很明顯這里使用了動態(tài)代理模式
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, @Nullable Object[] args)
throws Throwable {
//如果是java里面的基類不做處理
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 這個(gè)沒什么用android平臺默認(rèn)返回的是false的
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//非常重要的3行代碼
//解析方法的返回參數(shù) 請求參數(shù) 請求類型等
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
//很明顯OkHttp就知道他是一個(gè)網(wǎng)絡(luò)執(zhí)行器
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//很明顯他 肯定是調(diào)用了callAdapter
return serviceMethod.adapt(okHttpCall);
}
});
}
這里的代碼稍微有一丟丟復(fù)雜茬祷,主要理解代理模式。代理代理并蝗,不知道大家是否知道代購牲迫。比如你想買一件surpene的衣服,當(dāng)然superme肯定買不起借卧,只能買買faker。又拉下不臉筛峭,找了一個(gè)代購铐刘。
代理類會獲取被代理類的所有方法,并返回一個(gè)被代理類的對象影晓,這個(gè)對象就是虛擬的你镰吵,通過它去購買需要的商品。Proxy.newProxyInstance(xxx)是固定用法挂签,只要傳入xxx.class參數(shù)就行疤祭。
//固定格式
ClassLoader classLoader =Shop.class.getClassLoader();
//固定格式,三個(gè)參數(shù)饵婆,傳入Shop.class參數(shù)勺馆,獲取所有方法,返回代理對象侨核。
Shop shopProy = (Shop) Proxy.newProxyInstance(classLoader, new Class[]{IShop.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//回調(diào)原來類的方法草穆,該怎么做就怎么做
Object result = method.invoke(proxy,args);
//也可以自己實(shí)現(xiàn) 不回調(diào)原來的方法。
//.............................
return result;
}
});
這里的Invoke方法搓译,就是代理方法的實(shí)現(xiàn)悲柱,method.invoke()代表了回調(diào)原來的方法,這里也可以自己去實(shí)現(xiàn)方法些己,只要返回對應(yīng)的類型豌鸡。代理模式優(yōu)點(diǎn)就是提供了一個(gè)攔截接口,不管你什么方法調(diào)用都會先進(jìn)入Invoke段标。具體內(nèi)容可以學(xué)習(xí)JAVA反射來加深印象涯冠。
.........................................
//validateEagerly 這個(gè)變量主要是作用是 是否提前加入緩存
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//很明顯這里使用了動態(tài)代理模式
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, @Nullable Object[] args)
throws Throwable {
//.............................
//非常重要的3行代碼
//解析方法的返回參數(shù) 請求參數(shù) 請求類型等 關(guān)鍵代碼1
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
//很明顯OkHttp就知道他是一個(gè)網(wǎng)絡(luò)執(zhí)行器 關(guān)鍵代碼2
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//很明顯他 肯定是調(diào)用了callAdapter 關(guān)鍵代碼3
return serviceMethod.adapt(okHttpCall);
}
回到代理創(chuàng)建接口實(shí)例的方法中,我們創(chuàng)建接口的時(shí)候都是只寫了方法名怀樟,沒有具體的實(shí)現(xiàn)功偿,所以在代理對象并不能回調(diào),它只能自己去實(shí)現(xiàn)而且還要返回你要想的結(jié)果類型⌒岛桑苦b肮菜!!
public interface RetrofitService {
//沒有方法體 只有名字 怎么破(只能靠retrofit給我們實(shí)行)
@GET
Observable<ResponseBody> download(@Url String url);
// 沒有方法體吨瞎,只有名字 怎么破
@GET
Call<ResponseBody>download(@Url String url);
}
在retrofi中痹兜,利用了ServceMehod這個(gè)類來進(jìn)行實(shí)現(xiàn)方法體,它會獲取到接口方法的參數(shù)颤诀,返回值類型字旭,請求方式等所有參數(shù)⊙陆校看一下關(guān)鍵代碼1遗淳,loadServiceMethod()!心傀!
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//搞個(gè)緩存啊 美滋滋
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//緩存里面沒有,說明是第一次調(diào)用屈暗,安排一下,并且加入緩存
result = new ServiceMethod.Builder<>(this, method).build();//我只是一個(gè)建造者脂男,傳入了retrofit的對象养叛,擁有了adapterFactorese等所有屬性。
serviceMethodCache.put(method, result);
}
}
return result;
}
代碼很簡單宰翅,對調(diào)用的方法做一個(gè)緩存弃甥,第一次調(diào)用的時(shí)候才會去解析方法,其他情況下會使用緩存汁讼。同時(shí)我們也應(yīng)該知道validateEagerly這個(gè)Flag的作用了淆攻,如果你設(shè)置為true會創(chuàng)建動態(tài)代理對象的時(shí)候?qū)⑺械姆椒ń馕鼍彺妫駝t就只會在第一次調(diào)用的時(shí)候去緩存掉缺。
雖然已經(jīng)知道了ServiceMethod會對我們請求的方法進(jìn)行一頓瞎x操作卜录,各種解析分析組裝,但是我們還要要去看看實(shí)況眶明,它采用了建造者模式(builder)艰毒,直接看.build()方法。
public ServiceMethod build() {
..........................................//
//根據(jù)返回值類型搜囱,在adapterFactories的list里面去尋找CallAdapter丑瞧,如observeable,就會尋找RxjavCallAdapter.Factory 工廠模式產(chǎn)生CallAdapter 的對象蜀肘。
callAdapter = createCallAdapter();
//獲取返回值中的數(shù)據(jù)類型
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
//根據(jù)CallAdapter的返回的值中的數(shù)據(jù)類型(如: Call<Bean> download()绊汹, 就會根據(jù) ‘ Bean’去尋找Gson轉(zhuǎn)換器)去遍歷converterList找轉(zhuǎn)換器,Converter 的對象扮宠。
responseConverter = createResponseConverter();
//遍歷方法中的所有注解 一頓操作保存起來西乖。
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
int parameterCount = parameterAnnotationsArray.length;
// 保存請求參數(shù)的工具類
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
..................///
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
..................//
//遍歷方法參數(shù)中的所有注解和變量到parameterHandlers
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
.......................//
//返回一個(gè) ServiceMethod的實(shí)例
return new ServiceMethod<>(this);
}
主要作用是根據(jù)方法的返回值類型,獲取相應(yīng)的網(wǎng)絡(luò)適配器、數(shù)據(jù)轉(zhuǎn)換器以及拆卸參數(shù)類型等保存在parameterHandlers中获雕。列如:createCallAdapter會去遍歷callAdapterFactories找到相應(yīng)的callAdapter薄腻。
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
//.......................................................
//根據(jù)返回值遍歷callAdapterFactories
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
// get返回了一個(gè)CallAdapter對象
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//這里假設(shè)我們返回值是 Call<Bean> 類型的 ,默認(rèn)的ExecutorCallAdapterFactory會被匹配到届案♀挚看看它的get方法
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
//給力呀 鐵子 返回了一個(gè) CallAdapter對象
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
// 我就是方法體啊鐵子
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
其中Calladapter中的adapt方法就是方法體了。后續(xù)詳細(xì)介紹這個(gè)CallAdapter類楣颠。
根據(jù)關(guān)鍵代碼1, loadServiceMethod()返回了一個(gè)ServiceMethod的實(shí)例尽纽,它里面包含了你調(diào)用方法的所有信息,包含注解童漩,參數(shù)類型弄贿,參數(shù)名,返回值類型等矫膨,來看看它里面主要的屬性:
final class ServiceMethod<R, T> {
.............................//
//這個(gè)是Okhttp的工廠實(shí)例挎春,用來生產(chǎn)請求call的
private final okhttp3.Call.Factory callFactory;
//橋梁callAdapter 實(shí)例 發(fā)請求都是它在操作okhttp
private final CallAdapter<R, T> callAdapter;
// 8 必再說
private final HttpUrl baseUrl;
//數(shù)據(jù)轉(zhuǎn)換器實(shí)例
private final Converter<ResponseBody, R> responseConverter;
.......................//
//存儲請求參數(shù)的集合
private final ParameterHandler<?>[] parameterHandlers;
到此Retrofi已經(jīng)實(shí)現(xiàn)了高度的解耦,定義一個(gè)請求方法豆拨,我只想調(diào)用一下得到結(jié)果,至于怎么請求的能庆,和怎么轉(zhuǎn)換結(jié)果都不想關(guān)注施禾。retrofit在這里使用了外觀模式,只用定義方法入口(Retrofit.create(YourInterface.Class))搁胆,減少了對內(nèi)部細(xì)節(jié)的依賴弥搞,里面發(fā)生了變化,我們也不用擔(dān)心渠旁。
繼續(xù)看關(guān)鍵代碼2:
//很明顯這里使用了動態(tài)代理模式
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, @Nullable Object[] args)
throws Throwable {
//.............................
//非常重要的3行代碼
//解析方法的返回參數(shù) 請求參數(shù) 請求類型等 關(guān)鍵代碼1
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
//很明顯OkHttp就知道他是一個(gè)網(wǎng)絡(luò)執(zhí)行器 關(guān)鍵代碼2
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//很明顯他 肯定是調(diào)用了callAdapter 關(guān)鍵代碼3
return serviceMethod.adapt(okHttpCall);
}
將servcieMethod傳入到oKhttpCall攀例,serviceMethod已經(jīng)把請求參數(shù)拆卸下來存儲在了parameterHandlers中,OkHttpCall會取出參數(shù)類型和值進(jìn)行組裝請求顾腊。
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;//含有所有網(wǎng)絡(luò)請求參數(shù)類型等等
private final @Nullable Object[] args;//請求參數(shù)的值
private volatile boolean canceled;//取消請求Falg
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;//真正發(fā)請求的Okhttp
............................................//
}
OkHttpCall里面有了okhttp對象粤铭,使用它來進(jìn)行發(fā)請求操作,具體我們往下看杂靶。
關(guān)鍵代碼3:
//很明顯他 肯定是調(diào)用了callAdapter 關(guān)鍵代碼3
return serviceMethod.adapt(okHttpCall);
// 在ServiceMethod中adapt 調(diào)用了callAdapter
final class ServiceMethod {
..................................//
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
...............................//
}
將生產(chǎn)好的Call對象傳入到adapter中梆惯,然后開始實(shí)現(xiàn)方法體.
這里結(jié)合實(shí)例來看:
//我想要Call類型的返回值,使用默認(rèn)CallAdapter的就行了
@GET
Call<Model>download(@Url String url);
//使用 mRetrofitService.downloadADfile(xxx),就是在調(diào)用 serviceMethod.adapt(okHttpCall);
Call<Model> call = mRetrofitService.downloadADfile("www.kawayi.com");
我們在這里的 "call = "返回的是什么呢吗垮?來看一哈肯定很簡單垛吗。
//根據(jù)剛返回類型'Call' 遍歷CallAdapterFactories循環(huán)出得到默認(rèn)CallAdapter
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
//返回了一個(gè)ExecutorCallbackCall對象 來看一哈
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
很顯然返回了一個(gè)ExecutorCallbackCall對象,ExecutorCallbackCall內(nèi)容并不是很復(fù)雜烁登。
//這里是ExecutorCallbackCall 繼承了Call
static final class ExecutorCallbackCall<T> implements Call<T> {
//回調(diào)執(zhí)行器怯屉,有自定義就用自定義否則就會使用platform這個(gè)對象生產(chǎn)出綁定主線程的回調(diào)
final Executor callbackExecutor;
//這里傳入的是OkhttpCall
final Call<T> delegate;
//構(gòu)造函數(shù),傳入了OkhttpCall,和回調(diào)執(zhí)行器锨络,裝飾模式安排安排
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
//執(zhí)行異步請求
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//回調(diào)執(zhí)行器 切換線程
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
.......................//
}
代碼很簡單赌躺,顯然CallAdapter的內(nèi)部類ExecutorCallbackCall擁有okhttp和回調(diào)執(zhí)行器,所有的一切操作都在是它在執(zhí)行了足删。這里使用了裝飾模式寿谴,加強(qiáng)了okhttCall。裝飾模式:就是不改變類文件和使用繼承的情況下失受,動態(tài)地?cái)U(kuò)展一個(gè)對象的功能讶泰,是一種代替繼承的方案。
C和A都繼承了B拂到,但C里面有A的對象痪署,所以他可以調(diào)用A的方法,而且能添加一些A中沒有的功能兄旬。如:
static final class ExecutorCallbackCall<T> implements Call<T> {
......................................//
//ExeCutorCallbackCall和delegate都繼承了Call狼犯,但ExeCutorCallbackCall有回調(diào)執(zhí)行,取消請求這些功能领铐,得到了加強(qiáng)悯森。
final Call<T> delegate;
這里的delegate得到了加強(qiáng),擁有了切換線程的功能绪撵。
總結(jié):retrofit.create(RetrofitService.class)瓢姻,使用了動態(tài)代理創(chuàng)建RetrofitService對象,并且對它接口中的方法進(jìn)行了實(shí)現(xiàn)音诈,根據(jù)返回值的類型幻碱,尋找CallAdapter和converter并且拆卸請求參數(shù),組裝請求细溅,最后返回了Call的對象褥傍。
1.3.3 返回值執(zhí)行網(wǎng)絡(luò)請求
根據(jù)實(shí)例來看源碼:
//我想要Call類型的返回值,使用默認(rèn)CallAdapter的就行了
@GET Call<Model>download(@Url String url);
//實(shí)際上就是在調(diào)用serviceMethod.adapt(okHttpCall);
Call<Model> call = mRetrofitService.downloadADfile("www.kawayi.com");
//發(fā)一個(gè)異步請求喇聊。
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
根據(jù)剛剛分析的代碼可以知道恍风,返回的call對象是ExecutorCallbackCall的實(shí)例,enque執(zhí)行異步請求的誓篱,就會調(diào)用ExecutorCallbackCall的enque方法邻耕。
//這里是ExecutorCallbackCall 繼承了Call
static final class ExecutorCallbackCall<T> implements Call<T> {
//執(zhí)行異步請求
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
//okhttpCall去執(zhí)行請求,奧給力燕鸽。
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//這只是一個(gè)回調(diào)執(zhí)行器兄世,切換線程
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
.......................//
}
代碼中可以看到,我們傳入的okHttpCall(serviceMethod.adapt(okHttpCall))會調(diào)用okttp去執(zhí)行請求啊研,并且用回調(diào)執(zhí)行器回調(diào)okhttp返回的數(shù)據(jù)數(shù)據(jù)御滩。
下面來看看okHttp具體是怎么處理的
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;//含有所有網(wǎng)絡(luò)請求參數(shù)類型等等
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;//真正發(fā)請求的Okhttp
............................................//
//發(fā)一個(gè)異步請求鸥拧。實(shí)際上是okhttp操作
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
//okhttp的實(shí)例
okhttp3.Call call;
..............................................\\
call = rawCall = createRawCall() ;//拿到parameterHandlers的參數(shù)削解,組裝一個(gè)請求
...........................................\\
//真正的發(fā)一個(gè)請求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//使用數(shù)據(jù)轉(zhuǎn)換器富弦,轉(zhuǎn)換一下就完事了。
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
//回到到對應(yīng)的CallbackCall中氛驮,默認(rèn)是ExecutorCallbackCall
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
OkhttpCall首先先對請求進(jìn)行一個(gè)組裝腕柜,然后賦值給一個(gè)okhttp.Call的對象。通過call對象去發(fā)起請求矫废,中間有異常超時(shí)對應(yīng)的處理盏缤,拿到正確的請求結(jié)果之后,解析數(shù)據(jù)蓖扑,回調(diào)到對應(yīng)的CallbackCall唉铜,默認(rèn)是ExecutorCallbackCall,最后在ExecutorCallbackCall中使用回調(diào)執(zhí)行器再次回調(diào)律杠。
2.1 總結(jié)
1潭流、Retrofit對oKHttp層層封裝,利用動態(tài)代理模式柜去,實(shí)現(xiàn)接口定義的方法灰嫉。
2、根據(jù)返回值類型匹配對應(yīng)的CallAdapter嗓奢,converter熬甫,這里使用了策略模式。在對應(yīng)的callAdapter中使用了裝飾器模式并且返回了一個(gè)加強(qiáng)的Call對象蔓罚。
3、利用返回的Call對象來發(fā)請求瞻颂,利用內(nèi)部包裝的OkHttp對象豺谈,執(zhí)行請求。結(jié)果返回之后贡这,converter解析數(shù)據(jù)茬末,經(jīng)過層層回調(diào),到最后回調(diào)執(zhí)行器切換線程盖矫。
參考文獻(xiàn)
[1]劉望舒.Android進(jìn)階之光