Retrofit2源碼解析——網絡調用流程(上)

Retrofit2源碼解析系列

本文基於Retrofit2的2.4.0版本緩存

implementation 'com.squareup.retrofit2:retrofit:2.4.0'
複製代碼

網絡調用流程分析

咱們在發起異步網絡請求時是這樣調用的:bash

MyService myService = retrofit.create(MyService.class);
Call<IpBean> call = myService.getData();
call.enqueue(new Callback<IpBean>() {
    @Override
    public void onResponse(Call<IpBean> call, Response<IpBean> response) {
        
    }

    @Override
    public void onFailure(Call<IpBean> call, Throwable t) {
        
    }
});
複製代碼

總結起來就是三步:經過create方法生成咱們的接口對象、調用接口獲得Call、調用Call發起網絡請求。咱們分別來看看這三步Retrofit2都幹了些啥。微信

建立接口對象

//Retrofit.class
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 {
                    // If the method is a method from Object then defer to normal invocation.
                    if (method.getDeclaringClass() == Object.class) {
                        return method.invoke(this, args);
                    }
                    //這裏默認返回是false,因此不會執行
                    if (platform.isDefaultMethod(method)) {
                        return platform.invokeDefaultMethod(method, service, proxy, args);
                    }
                    //建立serviceMethod
                    ServiceMethod<Object, Object> serviceMethod =
                            (ServiceMethod<Object, Object>) loadServiceMethod(method);
                    //建立OkHttpCall,用於進行網絡請求
                    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    //返回通過適配器適配後的okHttpCall
                    return serviceMethod.adapt(okHttpCall);
                }
            });
}
複製代碼

能夠看到Retrofit的create方法返回的是一個動態代理對象,當咱們調用經過create方法生成的接口對象myService時,就會調用代理對象的invoke方法。在invoke方法中作了幾件事:網絡

(1)根據調用的具體方法Method(好比咱們調用的getData方法),生成ServiceMethod異步

(2)用生成的ServiceMethod和方法中的參數生成OkHttpCall用於後面調用OkHttp3請求網絡ide

(3)將生成的OkHttpCall經過Call適配器適配之後返回,也就是將OkHttpCall轉換成須要的Call類型,好比Retrofit2的Call,RxJava的Observable等,供咱們調用。post

調用接口獲得Call

咱們調用接口myService的getData方法時,會調用上面提到的動態代理對象的invoke方法,invoke方法會分別建立ServiceMethod、OkHttpCall,並將OkHttpCall適配返回咱們須要的Call對象。下面咱們來深刻源碼看看Retrofit是怎麼作這些事兒的。ui

(1)首先咱們看看是怎麼建立ServiceMethod的。this

//Retrofit.class
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
        result = serviceMethodCache.get(method);
        if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
        }
    }
    return result;
}
複製代碼

Retrofit中利用ConcurrentHashMap對ServiceMethod進行了緩存,建立ServiceMethod時會先去緩存中找,緩存中沒有的話再調用ServiceMethod的Builder建立。由於Retrofit會爲咱們寫的接口類中的每個方法都建立一個ServiceMethod,因此ServiceMethod的數量會不少,利用緩存能夠提升效率。spa

public ServiceMethod build() {
    //找到該方法所須要的CallAdapter
    callAdapter = createCallAdapter();
    responseType = callAdapter.responseType();
    ...
    //找到該方法須要的返回類型轉換器
    responseConverter = createResponseConverter();
    
    //解析方法中的註解
    for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
    }

    ...
    //這裏省略解析參數中的註解步驟
    ...

    return new ServiceMethod<>(this);
}
複製代碼

ServiceMethod的build方法中除了解析方法和參數的註解,最重要的就是肯定該方法(每個方法對應一個ServiceMethod)的CallAdapter和ResponseConverter。咱們在構建Retrofit時能夠添加多個CallAdapter和ResponseConverter,而這些CallAdapter和ResponseConverter都存放在Retrofit的對應的列表中,因此這裏確定須要去Retrofit的列表裏找,咱們來看看。

//ServiceMethod.class
private CallAdapter<T, R> 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 {
        
        //經過retrofit的callAdapter方法來查找對應的CallAdapter
        return (CallAdapter<T, R>) 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來查找CallAdapter的,那咱們去Retrofit的callAdapter方法方法看看

//Retrofit.class
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
                                         Annotation[] annotations) {
    ...

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        if (adapter != null) {
            return adapter;
        }
    }

    ...
}
複製代碼

callAdapter方法中會遍歷callAdapterFactories列表中的CallAdapterFactory,並調用其get方法,嘗試獲取CallAdapter,若是CallAdapter不爲null,就說明是要找的CallAdapter。這裏咱們來簡單看下默認的CallAdapterFactory的get方法。

從本文的開頭的分析咱們知道,默認的CallAdapterFactory是Platform的內部類Android返回的ExecutorCallAdapterFactory

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    ...
    @Override
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        ...
    }
    
    ...
}
複製代碼

能夠看到,ExecutorCallAdapterFactory的get方法首先會判斷當前的返回類型是否是Call以及Call的子類,不是的話就返回null。因此這就是Retrofit從適配器列表中找到對應適配器的方法依據。好比咱們再來看看RxJava的適配器:

//RxJavaCallAdapterFactory.class
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    
    ...
    if (rawType != Observable.class && !isSingle && !isCompletable) {
      return null;
    }

    ...

    return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
        false);
}
複製代碼

因此當咱們接口須要的是Observable時,咱們就須要給Retrofit設置RxJava的適配器,這樣Retrofit在建立ServiceMethod時就能找到對應的RxJava適配器了。

(2)建立OkHttpCall

建立OkHttpCall比較簡單,直接調用構造方法就行

OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
}
複製代碼

(3)返回接口須要的Call對象

從上面的分析中咱們知道,是經過serviceMethod的adapt方法來返回目標Call對象的,那咱們來看看serviceMethod的adapt方法

T adapt(Call<R> call) {
    return callAdapter.adapt(call);
}
複製代碼

能夠看到調用的serviceMethod中的callAdapter的adapt方法,也就是在上面的建立ServiceMethod的過程當中肯定的CallAdapter的adapt方法。這裏咱們看看默認的CallAdapter的adapt方法,也就是ExecutorCallAdapterFactory的adapt方法

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {

    ...
    @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);
            }
        };
    }
    
    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); } }); } }); } @Override public Response<T> execute() throws IOException { return delegate.execute(); } ... } } 複製代碼

能夠看到,ExecutorCallAdapterFactory的adapt方法返回的是ExecutorCallAdapterFactory的內部類ExecutorCallbackCall,ExecutorCallbackCall內部有2部分組成,一個是回調執行器callbackExecutor,這個是用於將請求結果回調到主線程的;另外一是Call對象,這裏對應的就是OkHttpCall,由於咱們調用adapt方法傳入的就是OkHttpCall。

因此到這裏其實網絡調用的前半部分流程就清楚了:

咱們在調用咱們的接口方法myService的getData方法時,實際上調用的是Retrofit爲咱們生成的代理類的invoke方法,invoke方法會建立ServiceMethod和OkHttpCall,ServiceMethod中保存着對應CallAdapter和ResponseConverter,而後會調用ServiceMethod中的adapt方法利用CallAdapter將OkHttpCall轉換成咱們須要的Call類型並返回給咱們調用。當咱們調用Call進行網絡請求時實際上調用的就是OkHttpCall對應的方法。

下篇文章咱們再來分析下網絡調用的下半部分流程,也就是Retrofit是怎麼將OkHttp3請求返回的Response轉換成咱們實際須要的類型的?


歡迎關注個人微信公衆號,和我一塊兒天天進步一點點!
複製代碼

AntDream
相關文章
相關標籤/搜索