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

微信公眾號:JueCode

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

1.聲明的接口NetService怎么經(jīng)過create就能調(diào)用發(fā)起網(wǎng)絡(luò)請求?

2.接口中的方法可以返回Call,也可以返回其他類型,比如Observable,這之間有什么關(guān)系,或者經(jīng)過怎樣的轉(zhuǎn)化過程?

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

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, 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動態(tài)代理的方式來處理對方法的調(diào)用問題。這樣說可能比較抽象,簡單舉個栗子,通過動態(tài)代理就會返回Call對象。


public interface MyService{

  @Get("info")

  Call<User> 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())將服務(wù)器返回的response,提取出ResponseBody(json)轉(zhuǎn)化為User

this.responseConverter = builder.responseConverter; 

// 負責(zé)解析API定義時每個方法的參數(shù)

this.parameterHandlers = builder.parameterHandlers;

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

OkHttpCall實現(xiàn)Call接口,主要會用到的方法execute和enqueue,一個同步一個異步。

@Override
public Response<T> 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創(chuàng)建okhttp,創(chuàng)建過程先通過serviceMethod創(chuàng)建request,request傳入callFactory創(chuàng)建okhttp3.Call。最后通過okhttpCall調(diào)用execute,enqueue的調(diào)用過程類似,最后也是通過okhttp調(diào)用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:這個返回的是關(guān)注的類型,比如Call ,返回的是User的類型

returnType:這個是接口中方法的返回類型,比如Call那么返回的就是Call類型

public interface CallAdapter<T> {
        Type responseType();

        <R> T adapt(Call<R> 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的實現(xiàn)類

serviceMethod中的callAdapter通過callAdapter = createCallAdapter()創(chuàng)建

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中根據(jù)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中大量使用的設(shè)計模式,在public interface Converter 接口中也會使用。DefaultCallAdapterFactory沒有多少代碼,重點看下get方法

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

2.記下來會根據(jù)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;

        }

    }

當(dāng)然還沒完,我們在深入到Observable中一探究竟,我們看下異步CallEnqueueObservable的例子??梢钥吹綄嶋H執(zhí)行還是通過call.enqueue(callback)執(zhí)行。

    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()方法的分析過程就結(jié)束了,Retrofit是通過Java動態(tài)代理實現(xiàn)對接口方法的調(diào)用處理,通過解析方法的注解和參數(shù)封裝request,通過request去構(gòu)造HttpCall,再根據(jù)CallAdapter Factory對Call進行代理,其實內(nèi)部還是通過OkHttp的Call模式做實際工作。Retrofit中比較多的使用工廠模式,實現(xiàn)很好的解耦,很值得借鑒。這方面的文章可以借鑒http://m.itdecent.cn/p/45cb536be2f4
謝謝!

擴展閱讀:

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

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

歡迎關(guān)注公眾號:JueCode

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 在Android開發(fā)中,網(wǎng)絡(luò)請求十分常用 而在Android網(wǎng)絡(luò)請求庫中,Retrofit是當(dāng)下最熱的一個網(wǎng)...
    Carson帶你學(xué)安卓閱讀 71,518評論 48 395
  • 本文將順著構(gòu)建請求對象->構(gòu)建請求接口->發(fā)起同步/異步請求的流程,分析Retrofit是如何實現(xiàn)的。 開始之前,...
    zhuhf閱讀 1,687評論 0 10
  • 適配器模式上一篇文章我們已經(jīng)分析了Retrofit解析注解封裝進ServiceMethod的流程,讀者在這里要記住...
    andcoder閱讀 781評論 0 2
  • 簡介 剛接觸Retrofit的時候,就寫了一篇簡單的使用介紹:Retrofit 2.0基本使用方法,算是對Retr...
    Whyn閱讀 3,111評論 4 24
  • 昨天晚上從店里回家,頭忽然暈得厲害,一站起來就整個世界都在轉(zhuǎn),于是女兒在做作業(yè),我就一直躺她床上不敢動,一...
    我行我素1314閱讀 311評論 2 1

友情鏈接更多精彩內(nèi)容