Android開源項(xiàng)目原理系列
[搞定開源01] okhttp 3.10原理
[搞定開源02] okio 1.14原理
demo
interface Api {
@GET("v2/movie/top250")
fun getTopList(): Call<HttpResponse>
}
api用的是豆瓣一個(gè)接口。
val retrofit = Retrofit.Builder()
.baseUrl("http://api.douban.com")
.addConverterFactory(GsonConverterFactory.create(Gson()))
.build()
val api = retrofit.create(Api::class.java)
val call = api.getTopList()
call.enqueue(object : Callback<HttpResponse> {
override fun onResponse(call: Call<HttpResponse>, response: Response<HttpResponse>) {
println("response:${response.body()}")
}
override fun onFailure(call: Call<HttpResponse>, t: Throwable) {
}
})
網(wǎng)絡(luò)請(qǐng)求工作實(shí)際由OkHttp負(fù)責(zé),Retrofit是對(duì)網(wǎng)絡(luò)請(qǐng)求接口的封裝,簡(jiǎn)單的幾行就可以發(fā)送一次網(wǎng)絡(luò)請(qǐng)求。
歸納
面向?qū)ο蟮木W(wǎng)絡(luò)請(qǐng)求流程可以歸納為:
- 封裝網(wǎng)絡(luò)請(qǐng)求參數(shù)為對(duì)象;
- 發(fā)送網(wǎng)絡(luò)請(qǐng)求,同步或者異步,得到服務(wù)器響應(yīng)結(jié)果;
- 解析結(jié)果為對(duì)象。
Retrofit的工作是第1、3點(diǎn),OKHttp負(fù)責(zé)第2點(diǎn)。具體化Retrofit的工作流程為下面5點(diǎn),接下來正文也是通過這5點(diǎn)詳述:
- 創(chuàng)建Retrofit實(shí)例;
- 通過Java接口描述請(qǐng)求api,創(chuàng)建請(qǐng)求實(shí)例;
- 同步或者異步發(fā)送網(wǎng)絡(luò)請(qǐng)求;
- 數(shù)據(jù)轉(zhuǎn)換器解析數(shù)據(jù);
- 切換線程
理解Retrofit源碼主干并不困難,我也不打算深入到每個(gè)細(xì)節(jié)。Retrofit是設(shè)計(jì)模式的寶庫(kù),是我本文最想分析總結(jié)的。
- Retrofit外觀模式;
- Retrofit、ServiceMethod使用構(gòu)建者模式創(chuàng)建;
- 動(dòng)態(tài)代理實(shí)例化請(qǐng)求實(shí)例;
- 工廠模式創(chuàng)建CallAdapter適配器;

1、創(chuàng)建Retrofit
創(chuàng)建Retrofit實(shí)例用的是構(gòu)建者設(shè)計(jì)模式,主要關(guān)注有哪些參數(shù),默認(rèn)參數(shù)是什么,哪些參數(shù)是必須的。
- platform:當(dāng)前平臺(tái),預(yù)設(shè)了Java8和Android,不同平臺(tái)的初始參數(shù)有區(qū)別
- baseUrl:必填
- callFactory:默認(rèn)是OkHttpClient
- converterFactories:將響應(yīng)結(jié)果進(jìn)行轉(zhuǎn)換
- callAdapterFactories:對(duì)請(qǐng)求返回類型進(jìn)行轉(zhuǎn)換
- callbackExecutor:異步回調(diào)執(zhí)行
整個(gè)庫(kù)圍繞的是核心類Retrofit,只需要了解這個(gè)入口類就可以玩起來,內(nèi)部復(fù)雜的邏輯不需要考慮,這是外觀模式的體現(xiàn)。
2、網(wǎng)絡(luò)請(qǐng)求的描述
每個(gè)網(wǎng)絡(luò)請(qǐng)求api在Retrofit中是定義在接口里,我們知道需要調(diào)用retrofit.create()將接口實(shí)例化。這種操作比較新奇,具體是怎樣實(shí)現(xiàn)的?
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
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 {
//...
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
答案是通過動(dòng)態(tài)代理模式,運(yùn)行時(shí)生成接口的代理類。當(dāng)調(diào)用api里的方法時(shí),自動(dòng)調(diào)用動(dòng)態(tài)代理的invoke。一般的動(dòng)態(tài)代理會(huì)有具體的實(shí)現(xiàn)類,代理類在調(diào)用實(shí)現(xiàn)類前后加上諸如日志的操作,這里就不需要了。
invoke核心是最后三行代碼:
- api里每個(gè)請(qǐng)求方法和網(wǎng)絡(luò)參數(shù),包裝為ServiceMethod類。ServiceMethod不是直接創(chuàng)建,而是通過一個(gè)名叫serviceMethodCache的Map進(jìn)行緩存,保持單例。真要?jiǎng)?chuàng)建時(shí),ServiceMethod使用了Builder設(shè)計(jì)模式,它包含了網(wǎng)絡(luò)請(qǐng)求的詳細(xì)參數(shù),具體創(chuàng)建邏輯不一一道來;
- ServiceMethod和請(qǐng)求參數(shù)包裝為retrofit2.OkHttpCall;
- 返回是接口retrofit2.Call,具體的類型需要通過CallAdapter轉(zhuǎn)換,比如返回RxJava的Observable。
CallAdapter
CallAdapter是Retrofit混雜著最多設(shè)計(jì)模式的一個(gè)接口,它的作用是將請(qǐng)求返回類型retrofit2.Call<R>轉(zhuǎn)為合適的類型T。顧名思義,首先它是一個(gè)適配器。
回看上面demo定義的一個(gè)api,默認(rèn)返回Call<HttpResponse>,使用RxJava就返回一個(gè)Observable。如果我們有需要,完全可以自行開發(fā)新的CallAdapter,返回MyCall<MyResponse>類型。
@GET("v2/movie/top250")
fun getTopList(): Call<HttpResponse>
看一眼源碼里的retrofit-adapters文件夾,Retrofit支持轉(zhuǎn)換的庫(kù)有:
- guava
- java8
- rxjava
- rxjava2
- scala
CallAdapter的創(chuàng)建需要用到CallAdapter.Factory,工廠模式,默認(rèn)工廠類是ExecutorCallAdapterFactory:
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
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);
}
};
}
工廠get函數(shù)返回CallAdapter的匿名實(shí)現(xiàn)類,將Object轉(zhuǎn)為ExecutorCallbackCall,這也是demo里call的類型。ExecutorCallbackCall的代碼不太多,大部分函數(shù)都委托給delegate處理,唯獨(dú)處理了異步請(qǐng)求的enqueue函數(shù)。
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) {
checkNotNull(callback, "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);
}
});
}
});
}
}
delegate實(shí)質(zhì)就是OkHttpCall,這里應(yīng)用了裝飾器模式,OkHttpCall原來的enqueue函數(shù)回調(diào)是在子線程執(zhí)行,ExecutorCallbackCall裝飾了enqueue函數(shù),將回調(diào)交由回調(diào)執(zhí)行器處理,在Android平臺(tái)也即是MainThreadExecutor,最終回調(diào)執(zhí)行在主線程。(線程切換后文第5點(diǎn))
3 發(fā)送請(qǐng)求
獲取retrofit2.Call對(duì)象后,就可以發(fā)送網(wǎng)絡(luò)請(qǐng)求了,分同步和異步兩個(gè)方法。畢竟Retrofit的定位是對(duì)OkHttp的封裝,收集的網(wǎng)絡(luò)請(qǐng)求信息轉(zhuǎn)換為okhttp3.Call交給OkHttp處理,最終得到OkHttp返回的Response,中間過程看OkHttp相關(guān)文章。
異步請(qǐng)求和同步請(qǐng)求類似,唯一不同的是執(zhí)行網(wǎng)絡(luò)請(qǐng)求后,回調(diào)需要在指定的線程執(zhí)行。
還有最后一步數(shù)據(jù)轉(zhuǎn)換調(diào)用了parseResponse函數(shù),將OkHttp的Response轉(zhuǎn)為Retrofit的Response,實(shí)質(zhì)調(diào)用了我們定義的Converter。
4 數(shù)據(jù)轉(zhuǎn)換Converter
數(shù)據(jù)轉(zhuǎn)換的作用是將結(jié)果ResponseBody轉(zhuǎn)為合適的類型,默認(rèn)的轉(zhuǎn)換器是BuiltInConverters,幾乎什么都無干。我常用的是GsonConverter,具體的解析過程不看了,
5 線程切換
異步得到服務(wù)器響應(yīng)后,需要將回調(diào)運(yùn)行在合適的線程。根據(jù)平臺(tái)的不同,提供不同的處理。
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
Android平臺(tái)默認(rèn)的CallbackExecutor是MainThreadExecutor,通過Handler切換線程到UI主線程。
用RxJava2CallAdapterFactory就更加方便了,自行設(shè)置。