Retrofit2 源碼閱讀

使用Retrofit作爲Android網絡請求已經非常普遍了,並且Retrofit的源碼不僅少而且還很精妙,作爲閱讀學習的對象在合適不過了。雖然很久之前就用了,但是還真沒看過源碼,趁着最近空閒就試着看看把。本文Retrofit版本是 2.6.0。看完我覺得還是2.4之前會更輕鬆點吧,可惜我沒找到老版本的jar包

基本用法

要了解一個框架的源碼,肯定要知道它的基本用法。然後從基本用法裏選擇一個入口方法,這樣就可以跟着用法讀下去了。

1、定義請求接口
public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<UserBean>> listRepos(@Path("user") String user);
}
2、初始化Retrofit
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .client(new OkHttpClient())
            //.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    GitHubService service = retrofit.create(GitHubService.class);
3、網絡請求
    Call<List<UserBean>> repos = service.listRepos("octocat");
    {
        repos.enqueue(new Callback<List<UserBean>>() {
            @Override
            public void onResponse(Call<List<UserBean>> call, Response<List<UserBean>> response) {
                List<UserBean> list = response.body();
            }

            @Override
            public void onFailure(Call<List<UserBean>> call, Throwable throwable) {

            }
        });
    }

源碼閱讀

從上面3個使用步驟我們可以很明顯的看出retrofit.create()是一個入口方法,首先先來看看Retrofit()中都初始化了啥。

一、Retrofit初始化

Retrofit通過Builder設計模式進行初始化。看一下build()方法中都做了些什麼。

public Retrofit build() {
	//初始化時baseUrl是必須的
    if(this.baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
    } else {
        Object callFactory = this.callFactory;
        //初始化時如果沒有設置client,callFactory 爲null
        //默認創建一個OkHttpClient賦值給callFactory 
        if(callFactory == null) {
            callFactory = new OkHttpClient();
        }
        Executor callbackExecutor = this.callbackExecutor;
        if(callbackExecutor == null) {
            callbackExecutor = this.platform.defaultCallbackExecutor();
        }
  		//調用addCallAdapterFactory時初始化
  		//如果沒有初始化,使用DefaultCallAdapterFactory
        ArrayList callAdapterFactories = new ArrayList(this.callAdapterFactories);
        callAdapterFactories.addAll(this.platform.defaultCallAdapterFactories(callbackExecutor));
        //調用addConverterFactory時候初始化,
        //如果沒有初始化使用默認的BuiltInConverters
        ArrayList converterFactories = new ArrayList(1 + this.converterFactories.size() + this.platform.defaultConverterFactoriesSize());
        converterFactories.add(new BuiltInConverters());
        converterFactories.addAll(this.converterFactories);
        converterFactories.addAll(this.platform.defaultConverterFactories());
        return new Retrofit((Factory)callFactory, this.baseUrl, Collections.unmodifiableList(converterFactories), Collections.unmodifiableList(callAdapterFactories), callbackExecutor, this.validateEagerly);
    }
}

構造Retrofit對象的時候初始化了三個非常重要的參數:

  • callFactory
  • CallAdapter
  • ConverterFactory

1、callFactory ,即OkHttpClient,繼承Call.Factory。OKhttp的工廠類
2、CallAdapter。適配器模式,負責將Call對象轉換成我們需要的類型。例如Rxjava中的Observable對象。

如下默認login返回Call對象,當時用初始化時調用addCallAdapterFactory(RxJava2CallAdapterFactory.create())給Retrofit添加一個RxJava的適配器的時候,則返回Observable對象

    // 使用默認適配器時
    Call<String> login();  

    // 添加Rxjava適配器時的返回
    Observable<String> login();  

3、ConverterFactory,轉換工廠。將http返回的response轉換成我們需要的對象。如UserBean。

二、構建service對象
 GitHubService service = retrofit.create(GitHubService.class);

create方法源碼如下:

    public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service);
        if(this.validateEagerly) {
            this.eagerlyValidateMethods(service);
        }

        return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
            private final Platform platform = Platform.get();
            private final Object[] emptyArgs = new Object[0];

            @Nullable
            public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
                return method.getDeclaringClass() == Object.class?method.invoke(this, args):(this.platform.isDefaultMethod(method)?
				this.platform.invokeDefaultMethod(method, service, proxy, args):
				Retrofit.this.loadServiceMethod(method).invoke(args != null?args:this.emptyArgs));
            }
        });
    }

Create方法中完成了兩件事情:

1、使用代理模式動態創建一個Service對象並返回

2、創建ServiceMethod對象,並且調用invoke()方法。

關於動態代理和反射可以我的另外兩篇文章:
代理模式
Java反射機制

創建ServiceMethod對象

通過loadServiceMethod()方法獲得一個ServiceMethod。

    ServiceMethod<?> loadServiceMethod(Method method) {
        ServiceMethod result = (ServiceMethod)this.serviceMethodCache.get(method);
        if(result != null) {
            return result;
        } else {
            Map var3 = this.serviceMethodCache;
            synchronized(this.serviceMethodCache) {
                result = (ServiceMethod)this.serviceMethodCache.get(method);
                if(result == null) {
                    result = ServiceMethod.parseAnnotations(this, method);
                    this.serviceMethodCache.put(method, result);
                }
                return result;
            }
        }
    }

可以看到loadServiceMethod()方法中有個會對ServiceMethod對象進行緩存,當ServiceMethod對象爲null時,會調用ServiceMethod.parseAnnotations(this, method)獲得一個ServiceMethod對象。

abstract class ServiceMethod<T> {
    ServiceMethod() {
    }

    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        Type returnType = method.getGenericReturnType();
        if(Utils.hasUnresolvableType(returnType)) {
            throw Utils.methodError(method, "Method return type must not include a type variable or wildcard: %s", new Object[]{returnType});
        } else if(returnType == Void.TYPE) {
            throw Utils.methodError(method, "Service methods cannot return void.", new Object[0]);
        } else {
            return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
        }
    }

    @Nullable
    abstract T invoke(Object[] var1);
}

從上面源碼可以看出ServiceMethod是一個抽象類。通過parseAnnotations()方法獲得一個ServiceMethod對象。

獲得RequestFactory

看一下ServiceMethod.parseAnnotations方法,首先會調用RequestFactory.parseAnnotations方法,獲得一個RequestFactory 對象

  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

那麼RequestFactory 又是什麼呢?

查看RequestFactory.parseAnnotations源碼如下

在這裏插入圖片描述

可以看到RequestFactory又是一個Builder模式。看一下Builder中的參數和方法
在這裏插入圖片描述
從上面的參數不難看出,這其實就是我們基本用法第一步中新建GitHubService 中的請求方法的解析。


    @GET("users/{user}/repos")
    Call<List<UserBean>> listRepos(@Path("user") String user);

比如解析上面的請求方法GET,路徑"users/{user}/repos",參數等等。

下面來看一下有哪些解析方法:

//解析Http請求的方法,get、post等
private void parseMethodAnnotation(Annotation annotation);
//解析Http請求的方法和路徑
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody);
//解析請求頭
private Headers parseHeaders(String[] headers)
//解析請求參數
private ParameterHandler<?> parseParameter(int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation)
//解析參數中的註解 例如@path。方法內調用ParameterHandler解析
 private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation)
 
static Set<String> parsePathParameters(String path);

解析方法時有個非常重要的類ParameterHandler,具體的解析是由ParameterHandler來完成的。

現在我們已經知道了RequestFactory的作用了,解析http請求的方法,路徑,請求頭等和http請求相關的參數了。

繼續回到我們的ServiceMethod類中。

    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        Type returnType = method.getGenericReturnType();
        if(Utils.hasUnresolvableType(returnType)) {
            throw Utils.methodError(method, "Method return type must not include a type variable or wildcard: %s", new Object[]{returnType});
        } else if(returnType == Void.TYPE) {
            throw Utils.methodError(method, "Service methods cannot return void.", new Object[0]);
        } else {
            return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
        }
    }

通過反射獲得方法的返回類型:
Type returnType = method.getGenericReturnType();

然後調用HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);獲得一個HttpServiceMethod對象。

HttpServiceMethod

HttpServiceMethod繼承自ServiceMethod。

HttpServiceMethod構造方法如下:

    HttpServiceMethod(RequestFactory requestFactory, Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) {
        this.requestFactory = requestFactory;
        this.callFactory = callFactory;
        this.responseConverter = responseConverter;
    }

需要初始化三個非常重要的參數:

  • requestFactory :service中的請求參數
  • callFactory :Call的適配器
  • responseConverter :response轉換器

HttpServiceMethod.parseAnnotations()源碼如下(有省略):

    static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
		...
        Annotation[] annotations = method.getAnnotations();
        Object adapterType;
        Type responseType;
		...
        adapterType = method.getGenericReturnType(); 
		//創建一個Call適配器
        CallAdapter callAdapter1 = createCallAdapter(retrofit, method, (Type)adapterType, annotations);
        //獲得返回類型
        responseType = callAdapter1.responseType();
		...
		//創建一個Converter
        Converter responseConverter = createResponseConverter(retrofit, method, responseType);
        Factory callFactory = retrofit.callFactory;
        return (HttpServiceMethod)(new HttpServiceMethod.CallAdapted(requestFactory, callFactory, responseConverter, callAdapter1);
	}

1、創建CallAdapter 對象

跟蹤createCallAdapter()方法,最終會調用Retrofit類中的nextCallAdapter()方法。源碼如下

    public CallAdapter<?, ?> nextCallAdapter(@Nullable retrofit2.CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
        Utils.checkNotNull(returnType, "returnType == null");
        Utils.checkNotNull(annotations, "annotations == null");
        int start = this.callAdapterFactories.indexOf(skipPast) + 1;
        int builder = start;

        int i;
        for(i = this.callAdapterFactories.size(); builder < i; ++builder) {
            CallAdapter count = ((retrofit2.CallAdapter.Factory)this.callAdapterFactories.get(builder)).get(returnType, annotations, this);
            //獲得一個不爲null的CallAdapter 並且返回
            if(count != null) {
                return count;
            }
        }
		...
        throw new IllegalArgumentException(var8.toString());
    }

nextCallAdapter()方法中遍歷callAdapterFactories集合中的CallAdapter,而callAdapterFactories則在Retrofit初始化的時候通過addCallAdapterFactory()賦值或者默認值。

當獲得一個不爲null的CallAdapter 的時候則返回。

2、創建Converter對象

通過responseType = callAdapter1.responseType();得到response類型。

通過Converter responseConverter = createResponseConverter(retrofit, method, responseType);創建一個responseConverter

跟蹤createResponseConverter()方法,最終在Retrofit中調用nextResponseBodyConverter()方法,源碼如下:

	public <T> Converter<ResponseBody, T> nextResponseBodyConverter(@Nullable retrofit2.Converter.Factory skipPast, Type type, Annotation[] annotations) {
        Utils.checkNotNull(type, "type == null");
        Utils.checkNotNull(annotations, "annotations == null");
        int start = this.converterFactories.indexOf(skipPast) + 1;
        int builder = start;

        int i;
        for(i = this.converterFactories.size(); builder < i; ++builder) {
            Converter count = ((retrofit2.Converter.Factory)this.converterFactories.get(builder)).responseBodyConverter(type, annotations, this);
            if(count != null) {
                return count;
            }
        }

        throw new IllegalArgumentException(var8.toString());
    }

同樣獲得Retrofit初始化時Converter 對象並返回。通過addConverterFactory()方法初始化或者使用默認的Converter 。

3、獲得callFactory

通過Factory callFactory = retrofit.callFactory;獲得一個Factory 對象。

同樣是在retrofit初始化的時候創建賦值。

4、返回HttpServiceMethod對象

new一個繼承自HttpServiceMethod 的 CallAdapted對象

    static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
        private final CallAdapter<ResponseT, ReturnT> callAdapter;

        CallAdapted(RequestFactory requestFactory, Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) {
            super(requestFactory, callFactory, responseConverter);
            this.callAdapter = callAdapter;
        }

        protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
            return this.callAdapter.adapt(call);
        }
    }

以上就是HttpServiceMethod類中的主要作用,到此ServiceMethod創建,我們需要再次回到Create()方法中。

創建OkHttpCall 對象

Create方法中完成了兩件事情:

1、使用代理模式動態創建一個Service對象並返回

2、創建ServiceMethod對象,並且調用invoke()方法。

上面ServiceMethod對象創建完畢,我們已經獲得一個ServiceMethod的實例對象HttpServiceMethod,現在執行HttpServiceMethod對象中的invoke()方法。

源碼如下:

    final ReturnT invoke(Object[] args) {
        OkHttpCall call = new OkHttpCall(this.requestFactory, args, this.callFactory, this.responseConverter);
        return this.adapt(call, args);
    }

在invoke方法中會創建並初始化一個OkHttpCall 對象,繼承Call對象。

三、請求網絡
    Call<List<UserBean>> call = service.listRepos("octocat");
    {
        call.enqueue(new Callback<List<UserBean>>() {
            @Override
            public void onResponse(Call<List<UserBean>> call, Response<List<UserBean>> response) {
            }

            @Override
            public void onFailure(Call<List<UserBean>> call, Throwable throwable) {
            }
        });
    }
1、call.queue()源碼

調用ApiService中的請求方法,獲得一個Call返回值,通過call.enqueue()執行網絡請求。

Call對象是一個接口,它的實現類是OkHttpCall ,所以真正網絡請求邏輯都在OkHttpCall 中

queue()方法源碼如下:

    public void enqueue(final Callback<T> callback) {

        okhttp3.Call call;//聲明一個okhttp請求call
        Throwable failure;
        	
        	...//省略一些空判斷,空處理
        	
        	//執行okhttp請求,Retrofit是基於okhttp3進行封裝的網絡請求框架,
        	//真正請求網絡的部分還是OKhttp
            call.enqueue(new okhttp3.Callback() {
            	//okhttp成功回調
                public void onResponse(okhttp3.Call call, Response rawResponse) {
                    retrofit2.Response response;
                    try {
                    	//解析成功的數據,返回我們需要的類型
                        response = OkHttpCall.this.parseResponse(rawResponse);
                    } catch (Throwable var6) {
                        Utils.throwIfFatal(var6);
                        this.callFailure(var6);
                        return;
                    }

                    try {
                    	//外部callback回調
                        callback.onResponse(OkHttpCall.this, response);
                    } catch (Throwable var5) {
                        Utils.throwIfFatal(var5);
                        var5.printStackTrace();
                    }
                }
				//OKhttp失敗回調
                public void onFailure(okhttp3.Call call, IOException e) {
                    this.callFailure(e);
                }				
                private void callFailure(Throwable e) {
                    try {
                    	//外部Callback回調
                        callback.onFailure(OkHttpCall.this, e);
                    } catch (Throwable var3) {
                        Utils.throwIfFatal(var3);
                        var3.printStackTrace();
                    }
                }
            });

    }

從源碼可以看到,真正執行網絡請求的是OKhttp,而當請求成功的時候,okhttp成功回調中有一行很重要的代碼:

 retrofit2.Response response;
 //解析OKhttp返回的rawResponse,轉換成我們需要的response
 response = OkHttpCall.this.parseResponse(rawResponse);
解析OKhttp成功返回結果

parseResponse()源碼如下:

    retrofit2.Response<T> parseResponse(Response rawResponse) throws IOException {
        ResponseBody rawBody = rawResponse.body();
        rawResponse = rawResponse.newBuilder().body(new OkHttpCall.NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();
        int code = rawResponse.code();
        if(code >= 200 && code < 300) {
            if(code != 204 && code != 205) {
                OkHttpCall.ExceptionCatchingResponseBody catchingBody1 = new OkHttpCall.ExceptionCatchingResponseBody(rawBody);

                try {
                	//將Body數據轉換成我們需要的類型
                    Object e1 = this.responseConverter.convert(catchingBody1);
                    return retrofit2.Response.success(e1, rawResponse);
                } catch (RuntimeException var9) {
                    catchingBody1.throwIfCaught();
                    throw var9;
                }
            } else {
                rawBody.close();
                return retrofit2.Response.success((Object)null, rawResponse);
            }
        } else {
          	...//省略
            return e;
        }
    }

這裏面也有段非常核心的代碼:

  Object e1 = this.responseConverter.convert(catchingBody1);

通過 responseConverter 調用 convert 方法實現類型轉換。

那麼responseConverter 是啥?

在這裏插入圖片描述
responseConverter 是一個Converter對象,負責將ResponseBody 轉換成 T 類型。

responseConverter 在哪賦值?
再來看一下
可以看到responseConverter 是在OKhttpCall的構造方法中進行初始化的

OKhttpCall的創建是在調用HttpServiceMethod 的 invoke() 方法中進行創建的,而responseConverter就是在HttpServiceMethod 中通過Converter responseConverter = createResponseConverter(retrofit, method, responseType);進行創建的。

到此從Retrofit初始化到網絡結束已經完成。
因爲在Retrofit初始化的時候,初始化了一個 defaultCallbackExecutor。

                Executor callbackExecutor = this.callbackExecutor;
                if(callbackExecutor == null) {
                    callbackExecutor = this.platform.defaultCallbackExecutor();
                }

而defaultCallbackExecutor 在Android平臺源碼如下

        public Executor defaultCallbackExecutor() {
            return new Platform.Android.MainThreadExecutor();
        }
        
        static class MainThreadExecutor implements Executor {
            private final Handler handler = new Handler(Looper.getMainLooper());

            MainThreadExecutor() {
            }

            public void execute(Runnable r) {
                this.handler.post(r);
            }
        }

可以看到這是一個在主線程的回調,所以我們可以直接在Retrofit的callback中進行進行ui操作。

Retrofit流程圖:

在這裏插入圖片描述

總結

Retrofit源碼閱讀到這裏了,其實還有不少爲什麼這樣做的問題還沒有消化,現在只是知道是這樣做這樣寫的。看之前也是做了些準備的,比如去學習了代理模式,反射,適配器模式,裝飾模式等。還好也沒準備一口氣喫個胖子,慢慢積累,過段時間再來看看會不會好點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章