前邊OkHttp的源碼順藤摸瓜校赤,摸了個(gè)遍堡牡。但是我們用的比較多的還是Retrofit则涯,都是square的佳作复局,它是在OKHttp上進(jìn)行了封裝,對(duì)開(kāi)發(fā)者變得更加友好粟判。本文基于retrofit: 2.9.0開(kāi)擼。
一、Retrofit在OKHttp上新增了什么魔法
- 使用動(dòng)態(tài)代理模式使用接口和注解方式定義請(qǐng)求方法赎败,對(duì)應(yīng)用層友好赚抡,使用容易理解和方便
- 它可以和RxJava配合使用,超級(jí)解耦
- 它可以定制很多解析轉(zhuǎn)換器呻澜,來(lái)將接口返回的數(shù)據(jù)封裝為我們的JavaBean對(duì)象
- 在請(qǐng)求回來(lái)后递礼,它會(huì)自動(dòng)切換為主線程,無(wú)需額外在應(yīng)用內(nèi)部進(jìn)行線程的切換
二羹幸、Retrofit的基本用法
Retrofit用法其實(shí)也不用多講脊髓,很簡(jiǎn)單:
- 首先,新建個(gè)請(qǐng)求接口類(lèi)
interface TestRetrofitService {
@GET("test")
fun getTestParms(): Call<ResponseBody>
}
- 再構(gòu)建一個(gè)全局的Retrofit實(shí)例栅受,它也是基于建造者模式
var retrofit: Retrofit = Retrofit.Builder().baseUrl("http://www.baidu.com").build()
- 然后使用Retrofit實(shí)例動(dòng)態(tài)生成一個(gè)請(qǐng)求接口的代理對(duì)象
var testRetrofitService: TestRetrofitService = retrofit.create(TestRetrofitService::class.java)
*4. 使用代理對(duì)象調(diào)用請(qǐng)求接口方法将硝,生成一個(gè)Call對(duì)象
val testCall: Call = testRetrofitService.getBaiduParms();
- 調(diào)用Call的enqueue方法,發(fā)起異步請(qǐng)求屏镊,execute方法則是同步請(qǐng)求
testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
TODO("Not yet implemented")
}
override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
TODO("Not yet implemented")
}
})
三依疼、Retrofit是如何通過(guò)建造者模式實(shí)例化的?
Retrofit.Builder().baseUrl("http://www.baidu.com").build()
- Retrofit有個(gè)Builder內(nèi)部類(lèi)而芥,它有兩個(gè)構(gòu)造方法律罢,它會(huì)傳入平臺(tái)類(lèi),并通過(guò)jvm虛擬機(jī)的名字判斷是Android平臺(tái)還是Java平臺(tái)棍丐。
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
private static Platform findPlatform() {
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new Android() //
: new Platform(true);
}
- 然后通過(guò)Retrofit.Builder實(shí)例可以傳入很多配置參數(shù)误辑,這和OKHttp一致,最后通過(guò)build()方法骄酗,實(shí)例化Retrofit
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
...
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
四稀余、Retrofit是如何通過(guò)動(dòng)態(tài)代理實(shí)例化請(qǐng)求接口類(lèi)的代理對(duì)象?
//請(qǐng)求接口類(lèi)
interface TestRetrofitService {
@GET("meinv")
fun getBaiduParms(): Call<ResponseBody>
}
//通過(guò)動(dòng)態(tài)代理實(shí)例化一個(gè)代理對(duì)象
var testRetrofitService = retrofit.create(TestRetrofitService::class.java)
跟蹤Retrofit.create()方法趋翻,映入眼前的就是妥妥的動(dòng)態(tài)代理模式了睛琳,Proxy.newProxyInstance()盒蟆。通過(guò)動(dòng)態(tài)代理返回了一個(gè)TestRetrofitService接口類(lèi)的代理對(duì)象
public <T> T create(final Class<T> service) {
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
...
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
...
158行 return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
五、Retrofit生成的動(dòng)態(tài)代理對(duì)象調(diào)用請(qǐng)求方法后师骗,如何返回的Call對(duì)象的历等?
val testCall: Call = testRetrofitService.getBaiduParms();
- 我們可以看到上面動(dòng)態(tài)代理158行,這里又是Android和java平臺(tái)的判斷辟癌,這里直接可以看到
loadServiceMethod(method).invoke(args)
- 在loadServiceMethod()方法中寒屯,它將對(duì)傳入的Method的注解進(jìn)行解析保存為一個(gè)ServiceMethod對(duì)象并緩存起來(lái)。
ServiceMethod<?> loadServiceMethod(Method method) {
//1. 首先沖緩存中獲取黍少,獲取到了就返回
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
//2. 為了線程安全問(wèn)題寡夹,加了鎖
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//3. 開(kāi)始解析Annotations
result = ServiceMethod.parseAnnotations(this, method);
//4. 將解析好的serviceMethod緩存起來(lái)
serviceMethodCache.put(method, result);
}
}
return result;
}
- ServiceMethod是一個(gè)抽象類(lèi),HttpServiceMethod為其子類(lèi)
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
26行 RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
...
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
- 如上26行厂置,它通過(guò)RequestFactory類(lèi)的parseAnnotations()方法解析請(qǐng)求接口類(lèi)的方法上和參數(shù)的注解菩掏。
在RequestFactory里實(shí)際也是通過(guò)建造者模式,返回了RequestFactory實(shí)例
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
通過(guò)查看Builder內(nèi)部類(lèi)中的build方法昵济,發(fā)現(xiàn)了很多解析Annotation注解的方法智绸。
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
181行 parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
205行 parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...
return new RequestFactory(this);
}
181行解析的是方法上的注解:這里大家看著都懂,無(wú)非就是解析方法上的一個(gè)@GET访忿、@POST等注解瞧栗,并獲取值,并保存在成員變量中
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
...
}
205行解析的是方法上的注解:這里就是將方法里的每個(gè)參數(shù)單獨(dú)保存為一個(gè)ParameterHandler實(shí)例
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
...
}
后續(xù)的如何解析海铆,大家可以深入代碼中看看迹恐,這里就不一一貼代碼了。比較簡(jiǎn)單游添,就是注解的解析取值系草,存值過(guò)程。
- 前邊的ServiceMethod.parseAnnotations()方法最終返回了一個(gè)HttpServiceMethod實(shí)例唆涝,而HttpserviceMethod是ServiceMethod的子類(lèi)
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
- 回到第2點(diǎn)找都,動(dòng)態(tài)代理最終返回的是loadServiceMethod(method).invoke(args),而loadServiceMethod(method)返回的是一個(gè)HttpServiceMethod的實(shí)例廊酣,我們看看它的invoke()方法能耻,這里就實(shí)例化了一個(gè)OKHttpCall對(duì)象,而它就是Call的子類(lèi)亡驰。這里其實(shí)它還被另外一個(gè)ExecutorCallbackCall包裝了一層(adapt(call, args)方法包裝)晓猛。這里先不講。
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
六凡辱、Retrofit如何通過(guò)Call實(shí)例對(duì)象發(fā)起請(qǐng)求的戒职?
testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
TODO("Not yet implemented")
}
override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
TODO("Not yet implemented")
}
})
前面知道了其實(shí)真正執(zhí)行請(qǐng)求的Call就是OKHttpCall,我們跟蹤enqueue()方法進(jìn)去看看透乾。
- 調(diào)用OKHttpCall.enqueue()方法
@Override
public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
synchronized (this) {
call = rawCall;
if (call == null && failure == null) {
try {
130行 call = rawCall = createRawCall();
} catch (Throwable t) {
}
}
}
147行 call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
callback.onResponse(OkHttpCall.this, response);
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callback.onFailure(OkHttpCall.this, e);
}
});
}
- 它在130行調(diào)用了createRawCall()方法洪燥,它調(diào)用了callFactory.newCall方法創(chuàng)建出okHttp3.Call對(duì)象
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
...
return call;
}
- 這里的callFactory實(shí)際上就是OKHttpClient磕秤,這在之前建造者模式創(chuàng)建Retrofit實(shí)例的build()方法中可以看到,而OkHttpClient.newCall()方法實(shí)際上就是返回了一個(gè)RealCall對(duì)象
public Retrofit build(){
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
...
}
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
- requestFactory.create(args)方法呢捧韵,就是返回了一個(gè)Request請(qǐng)求對(duì)象市咆。
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
...
RequestBuilder requestBuilder =
new RequestBuilder(
httpMethod,
baseUrl,
relativeUrl,
headers,
contentType,
hasBody,
isFormEncoded,
isMultipart);
...
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
- 回到1中的147行,call.enqueue()實(shí)際就是使用OKHttp的ReallCall對(duì)象開(kāi)始將請(qǐng)求進(jìn)行分發(fā)再来,或加入執(zhí)行隊(duì)列或加入等待隊(duì)列蒙兰。這里和之前寫(xiě)的《OKHttp源碼解析》請(qǐng)求流程一致了。然后在回調(diào)接口芒篷。
七搜变、Retrofit如何在返回response時(shí),切換到主線程可以直接渲染UI的梭伐?
這里講起來(lái)有點(diǎn)繞:
- 先回到Retrofit的創(chuàng)建來(lái)痹雅,在Build.buid()方法中,它會(huì)為Retrofit默認(rèn)添加平臺(tái)默認(rèn)的CallAdapter適配器工廠糊识,如android平臺(tái)就添加Android類(lèi)中的callbackExecutor(PS: Android是platform的子類(lèi),實(shí)現(xiàn)了defaultCallbackExecutor方法)
public Retrofit build() {
...
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
631行 callbackExecutor = platform.defaultCallbackExecutor();
}
638行 callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
...
}
- 631行獲取了平臺(tái)默認(rèn)的回調(diào)執(zhí)行器摔蓝,這里就是線程切換的地方赂苗,而Android是Platform內(nèi)部子類(lèi)。它返回了一個(gè)MainThreadExecutor()對(duì)象贮尉,而它實(shí)際上就是通過(guò)new Handler(Looper.getMainLooper())拌滋,Handler來(lái)實(shí)現(xiàn)切回主線程。
static final class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
八. 實(shí)際上這里已經(jīng)知道Retrofit怎么切換到主線程了猜谚,那么它在哪里調(diào)用的呢败砂?
- 在 上面七的638行,platform.defaultCallAdapterFactories(callbackExecutor)它通過(guò)傳入callBackExecuter魏铅,返回了一個(gè)平臺(tái)默認(rèn)的CallAdapterFactory適配器工廠昌犹。它實(shí)際上就是返回了一個(gè)DefaultCallAdapterFactory。
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
- 前邊我們說(shuō)在HttpServiceMethod.invoke()返回的是一個(gè)OKHttpCall對(duì)象览芳,其實(shí)不完全對(duì)斜姥,因?yàn)樗€被CallAdapter適配器包裝了一層。
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
- 2中所說(shuō)的CallAdapter適配器就是通過(guò)DefaultCallAdapterFactory工廠的get()方法生成的沧竟。
至于如何生成铸敏,給一個(gè)路線(是在動(dòng)態(tài)代理生成代理對(duì)象,并通過(guò)代理對(duì)象調(diào)用請(qǐng)求方法時(shí)):
- 2中所說(shuō)的CallAdapter適配器就是通過(guò)DefaultCallAdapterFactory工廠的get()方法生成的沧竟。
1. ServiceMethod.parseAnnotations()
2.HttpServiceMethod.parseAnnotations()
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
3. HttpServiceMethod.createCallAdapter()
4. Retrofit.callAdapter()
5. Retrofit.nextCallAdapter()
public CallAdapter<?, ?> nextCallAdapter(
CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
...
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
return adapter;
}
}
- 看到DefaultCallAdapterFactory.get()方法悟泵,它返回了一個(gè)CallAdapter對(duì)象杈笔。
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
47行 final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
- 47行:callbackExecutor實(shí)際就是1中的MainThreadExecutor,最后return CallAdapter糕非,在CallAdapter的adapt方法中返回了一個(gè)ExecutorCallbackCall對(duì)象
new ExecutorCallbackCall<>(executor, call)
- 這個(gè)傳入的參數(shù)call就是OKHttpCall, 而ExecutorCallbackCall就是包裝OKHttpCall的蒙具,它主要用來(lái)回調(diào)時(shí)做線程切換用途的敦第。它也是call的子類(lèi)。它是DefautlCallAdapterFactory內(nèi)部類(lèi)
static final class ExecutorCallbackCall<T> implements Call<T> {
@Override
public void enqueue(final Callback<T> callback) {
//1. delegate就是OKHttpCall店量,實(shí)際上就是OKHttpCall.enqueue()
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
//2. 請(qǐng)求返回后使用MainThreadExecutor對(duì)象切換線程
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
// 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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
}
- delegate就是OKHttpCall芜果,實(shí)際上就是OKHttpCall.enqueue()
- 請(qǐng)求返回后使用MainThreadExecutor對(duì)象切換線程
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
九、結(jié)語(yǔ)
我們通過(guò)Retrofit的主線了解清楚了融师,Retrofit如何通過(guò)動(dòng)態(tài)代理和注解反射等機(jī)制對(duì)OKHttp進(jìn)行封裝右钾。對(duì)于我們靈活使用Retrofit來(lái)開(kāi)發(fā)和解決使用Retrofit中遇到的問(wèn)題非常有幫助,另外也通過(guò)跟蹤框架源碼旱爆,對(duì)于搭建框架也有了更多的認(rèn)識(shí)和理論支撐舀射。