拆Retrofit2.0 的create()方法流程

yangxi_001發表於2017-06-22

滾滾長江東逝水,浪花也要乘風迎浪。一直在心裡感激在網上寫部落格的各路大神們,在開發過程中幫助很大,自己也有心向先輩們學習,一來對自己也是一種督促,寫部落格也是鞏固知識的過程,二來也希望能將自己開發中的所學記錄下來,說不定能幫助到某些程式猿呢?這也是我的第一篇部落格,內容如果有誤還請指出來。好了,廢話少說,進入正文。

Retrofit不用多介紹了,誰用誰知道。我在使用過程中會產生疑問:

1.宣告的介面NetService怎麼經過create就能呼叫發起網路請求?

2.介面中的方法可以返回Call,也可以返回其他型別,比如Observable,這之間有什麼關係,或者經過怎樣的轉化過程?

帶著這兩個疑問去探索下create()方法的執行流程。下面是該方法的原始碼,比較短我們直接貼上過來:

public  T create(final Class 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, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

我們的第一個疑問有解了,在create中會通過Java動態代理的方式來處理對方法的呼叫問題。這樣說可能比較抽象,簡單舉個栗子,通過動態代理就會返回Call物件。

public interface MyService{
@Get("info")
Call getUser();
}

重點是最後的三行程式碼。

1. ServiceMethod serviceMethod =(ServiceMethod)loadServiceMethod(method);

ServiceMethod官方解釋:

Adapts an invocation of an interface method into an HTTP call

有四個重要的成員:

//封裝call,預設是okHttpCall
this.callFactory = builder.retrofit.callFactory();
//最著名的RxJava,預設是不支援,通過新增.addCallAdapterFactory(RxJavaCallAdapterFactory.create())增加對Obsevable的支援
this.callAdapter = builder.callAdapter;
//addConverterFactory(GsonConverterFactory.create())將伺服器返回的response,提取出ResponseBody(json)轉化為User
this.responseConverter = builder.responseConverter;
// 負責解析API定義時每個方法的引數
this.parameterHandlers = builder.parameterHandlers;

2. okHttpCall = new OkHttpCall(serviceMethod, args);

OkHttpCall實現Call介面,主要會用到的方法execute和enqueue,一個同步一個非同步。

@Override
public Response execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}

可以看出,會通過createRawCall建立okhttp,建立過程先通過serviceMethod建立request,request傳入callFactory建立okhttp3.Call。最後通過okhttpCall呼叫execute,enqueue的呼叫過程類似,最後也是通過okhttp呼叫enqueue。

private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}

3. serviceMethod.callAdapter.adapt(okHttpCall)

有幾個概念需要注意下:

responseType:這個返回的是關注的型別,比如Call ,返回的是User的型別

returnType:這個是介面中方法的返回型別,比如Call那麼返回的就是Call型別

public interface CallAdapter {
Type responseType();
T adapt(Call call);
public abstract CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit);
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class getRawType(Type type) {
return Utils.getRawType(type);
}
}

callAdapter是介面public interface CallAdapter的實現類

serviceMethod中的callAdapter通過callAdapter = createCallAdapter()建立

private CallAdapter createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError("Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
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);
}
}

在retrofit中根據returnType從adapterFactories(List adapterFactories = new ArrayList();)中得到callAdapter

    public CallAdapter callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
…….
}

factories可以在初始化retrofit的時候新增,我們來看下預設的CallAdapter.Factory, 工廠模式,這個也是retrofit中大量使用的設計模式,在public interface Converter 介面中也會使用。DefaultCallAdapterFactory沒有多少程式碼,重點看下get方法

1.預設的模式只支援Call這種returnType,所以一進來會判斷是不是Call.class。

2.記下來會根據renturnType來獲得responseType,也就是上面例子中Call中的User型別。

3.最後會new一個CallAdapter,因為預設的是支援Call這種returnType,因此在adapt方法中直接返回call。

    final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@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 > () {
@Override public Type responseType () {
return responseType;
}
@Override public Call adapt (Call call){
return call;
}
} ;
}
}

4.我們再簡單看看RxJava2CallAdapterFactory

    public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
......
@Override
public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class rawType = getRawType(returnType);
......
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,isSingle, isMaybe, false);
}
}

在RxJava2CallAdapter中,看到熟悉的adapt方法,方法會將call封裝成Observable,最後我們就可以快樂的使用RxJava

    final class RxJava2CallAdapter implements CallAdapter {
@Override
public Type responseType() {
return responseType;
}
@Override
public Object adapt(Call call) {
Observable > responseObservable = isAsync
? new CallEnqueueObservable(call)
: new CallExecuteObservable(call);
……
return observable;
}
}

當然還沒完,我們在深入到Observable中一探究竟,我們看下非同步CallEnqueueObservable的例子。可以看到實際執行還是通過call.enqueue(callback)執行。

    final class CallEnqueueObservable extends Observable {
private final Call originalCall;
CallEnqueueObservable(Call originalCall) {
this.originalCall = originalCall;
}
@Override
protected void subscribeActual(Observer>observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call call = originalCall.clone();
CallCallback callback = new CallCallback(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);
}
private static final class CallCallback implements Disposable, Callback {
......
}
}

到這裡我們對create()方法的分析過程就結束了,Retrofit是通過Java動態代理實現對介面方法的呼叫處理,通過解析方法的註解和引數封裝request,通過request去構造HttpCall,再根據CallAdapter Factory對Call進行代理,其實內部還是通過OkHttp的Call模式做實際工作。Retrofit中比較多的使用工廠模式,實現很好的解耦,很值得借鑑。這方面的文章可以借鑑http://www.jianshu.com/p/45cb536be2f4。
謝謝!

擴充套件閱讀:

https://blog.piasy.com/2016/06/25/Understand-Retrofit/

http://blog.csdn.net/lmj623565791/article/details/51304204

轉自:http://www.jianshu.com/p/4d0eae0bc40c

相關文章