Retrofit原理分析

一远搪、Retrofit簡介

Retrofit是現(xiàn)下Android端開發(fā)非常流行的一款網絡請求框架,它通過動態(tài)代理的方式將Java接口翻譯成網絡請求,通過OkHttp發(fā)送請求客燕,并且其具備強大的可擴展性,支持各種數(shù)據(jù)格式的轉換以及RxJava狰贯。說到這里也搓,我們來分析一下網絡請求框架的本質赏廓,網絡請求框架是一套提供給開發(fā)者使用的用于網絡請求的API接口,我們知道傍妒,Android網絡請求一般是基于Http協(xié)議的幔摸,而Http協(xié)議屬于應用層的協(xié)議,具體的數(shù)據(jù)傳輸需要依賴傳輸層的TCP協(xié)議颤练,Android系統(tǒng)提供了Socket編程接口給開發(fā)者建立TCP請求既忆,所以具體數(shù)據(jù)的發(fā)送需要依賴Socket;Http協(xié)議屬于應用層的協(xié)議昔案,它是用來規(guī)定數(shù)據(jù)的傳輸格式的尿贫,用于傳輸雙方都能按照固定的格式解讀數(shù)據(jù);所以踏揣,一個網絡請求框架至少要包含以下幾個功能:

1庆亡、提供接口給開發(fā)者傳入請求參數(shù);

2捞稿、編寫Socket代碼又谋,建立TCP;

3娱局、通過TCP連接彰亥,嚴格按照Http協(xié)議的格式將請求參數(shù)發(fā)送給服務端;

4衰齐、嚴格按照Http協(xié)議的格式解讀服務端返回的數(shù)據(jù)任斋;

5、提供相應的接口給開發(fā)者獲得返回數(shù)據(jù)(一般是通過回調處理的)耻涛。

上面五點是一個網絡請求框架必須具備的功能废酷,當然,一個好的網絡請求框架還應該具備如下特點:

1抹缕、提供給開發(fā)者使用的API盡可能簡單澈蟆;

2、添加了對網絡緩存的處理卓研,避免不必要的請求趴俘;

3、具有較高的性能奏赘;

4寥闪、具有較高的可擴展性。

我們常用的OkHttp磨淌、HttpURLConnection等網絡請求框架橙垢,其內部就會將開發(fā)者傳入的請求參數(shù)按照Http協(xié)議的格式組織好,并通過TCP連接發(fā)送給服務端伦糯,在收到服務端返回數(shù)據(jù)后柜某,又會按照Http協(xié)議去解讀數(shù)據(jù),并提供相應的API(一般是回調)給開發(fā)者獲得數(shù)據(jù)敛纲。由于OkHttp屬于比較底層的網絡請求框架喂击,開發(fā)者在使用時還是會比較復雜,于是Retrofit對OkHttp進行了再度的封裝淤翔,使得開發(fā)者在使用時更加的方便翰绊。

二、使用Retrofit請求網絡數(shù)據(jù)的基本流程

1旁壮、在build中添加依賴

compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

2监嗜、定義請求接口類

import retrofit2.Call;

import retrofit2.http.Field;

import retrofit2.http.FormUrlEncoded;

import retrofit2.http.POST;

/**

* Created by dell on 2018/9/6.

*/

public interface TranslateApi {

? ? @POST("ajax.php?a=fy&f=auto&t=auto")

? ? @FormUrlEncoded

? ? Call<TranslateBean> translateRequest(@Field("w") String input);

}

3、創(chuàng)建Retrofit實例

Retrofit retrofit = new Retrofit.Builder() // 通過Builder模式構造一個Retrofit對象

? ? ? ? ? ? ? ? .baseUrl("http://fy.iciba.com/") // 配置HOST

? ? ? ? ? ? ? ? .addConverterFactory(GsonConverterFactory.create()) // 添加解讀返回數(shù)據(jù)的對象抡谐,因為返回數(shù)據(jù)是Json格式的裁奇,所以這里采用GsonConverterFactory來解讀

? ? ? ? ? ? ? ? .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 添加適配OkHttpCall對象的CallAdapterFactory

? ? ? ? ? ? ? ? .build();

4、根據(jù)請求接口生成具體的請求實體對象

TranslateApi translateApi = retrofit.create(TranslateApi.class); // 傳入定義的接口麦撵,獲得一個實現(xiàn)了TranslateApi接口的實體對象

5刽肠、調用請求對象的請求方法生成能夠發(fā)起網絡請求的Call對象

Call<TranslateBean> call = translateApi.translateRequest(mInputEditText.getText().toString()); // 調用請求方法,返回一個Call對象

6免胃、調用Call對象的enqueue方法發(fā)起異步網絡請求

? ? ? ? call.enqueue(new Callback<TranslateBean>() { // 調用Call對象的enqueue方法發(fā)起異步網絡請求音五,enqueue方法需要傳入一個Callback對象,用來處理網絡請求的回調

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onResponse(Call<TranslateBean> call, Response<TranslateBean> response) { // 網絡請求正確的回調

? ? ? ? ? ? ? ? TranslateBean translateBean = response.body(); // 處理返回結果

? ? ? ? ? ? ? ? if (translateBean.getContent().getOut() != null) {

? ? ? ? ? ? ? ? ? ? mOutputText.setText(translateBean.getContent().getOut());

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? mOutputText.setText(translateBean.getContent().getWordMeanString());

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onFailure(Call<TranslateBean> call, Throwable t) { // 網絡請求錯誤的回調

? ? ? ? ? ? ? ? mOutputText.setText("翻譯出錯了羔沙!");

? ? ? ? ? ? }

總結一下躺涝,首先我們定義了網絡請求的接口,接口中配置了請求的基本信息扼雏,包括請求方法坚嗜、請求參數(shù)等;接著我們生成了一個Retrofit對象呢蛤,在這里可以配置請求的默認Host信息惶傻、添加解析返回數(shù)據(jù)格式的Factory、添加適配OkHttpCall的Factory等功能其障;然后調用retrofit對象的create方法银室,傳入網絡請求接口類,生成一個具體的網絡請求實體對象励翼;接下來我們調用了請求方法生成一個能夠發(fā)起網絡請求的Call對象蜈敢,最后調用Call對象的enquene方法將發(fā)起異步的網絡請求,并且在傳入的Callback中處理網絡請求的回調汽抚。

三抓狭、Retrofit原理分析

從上面的使用方法可以看出,Retrofit的核心是根據(jù)接口生成一個能夠發(fā)起網絡請求的對象造烁,然后根據(jù)這個對象再發(fā)起網絡請求

1否过、生成Retrofit對象

? ? public Retrofit build() {

? ? ? if (baseUrl == null) {

? ? ? ? throw new IllegalStateException("Base URL required.");

? ? ? }

? ? ? okhttp3.Call.Factory callFactory = this.callFactory;

? ? ? if (callFactory == null) {

? ? ? ? callFactory = new OkHttpClient(); // 如果沒有設置網絡請求框架午笛,模式使用OkHttp處理網絡請求

? ? ? }

? ? ? Executor callbackExecutor = this.callbackExecutor;

? ? ? if (callbackExecutor == null) {

? ? ? ? callbackExecutor = platform.defaultCallbackExecutor(); // 默認使用platform.defaultCallbackExecutor()處理返回結果

? ? ? }

? ? ? // Make a defensive copy of the adapters and add the default Call adapter.

? ? ? List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);

? ? ? adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

? ? ? // Make a defensive copy of the converters.

? ? ? List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

? ? ? return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,

? ? ? ? ? callbackExecutor, validateEagerly); // 根據(jù)配置信息生成一個Retrofit對象

? ? }

? }

Retrofit通過build模式來生成一個Retrofit對象,通過代碼我們知道苗桂,Retrofit默認會使用OkHttp來發(fā)送網絡請求药磺,當然,我們也可以自己定制煤伟。

2癌佩、create方法根據(jù)接口生成具體的網絡請求實體類

public <T> T create(final Class<T> service) {

? ? Utils.validateServiceInterface(service);

? ? if (validateEagerly) {

? ? ? eagerlyValidateMethods(service);

? ? }

? ? return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, // 通過動態(tài)代理的方式生成具體的網絡請求實體對象

? ? ? ? new InvocationHandler() { // 統(tǒng)一處理所有的請求方法

? ? ? ? ? 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);

? ? ? ? ? ? }

? ? ? ? ? ? if (platform.isDefaultMethod(method)) {

? ? ? ? ? ? ? return platform.invokeDefaultMethod(method, service, proxy, args);

? ? ? ? ? ? }

? ? ? ? ? ? ServiceMethod<Object, Object> serviceMethod =

? ? ? ? ? ? ? ? (ServiceMethod<Object, Object>) loadServiceMethod(method);? // 根據(jù)方法生成一個ServiceMethod對象(內部會將生成的ServiceMethod放入在緩存中,如果已經生成過則直接從緩存中獲缺阆恰)

? ? ? ? ? ? OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); // 根據(jù)ServiceMethod對象和請求參數(shù)生成一個OkHttpCall對象围辙,這個OkHttpCall能夠調用OkHttp的接口發(fā)起網絡請求

? ? ? ? ? ? return serviceMethod.callAdapter.adapt(okHttpCall); // 調用serviceMethod的callAdapter的adapt方法,并傳入okHttpCall放案,返回一個對象姚建,這個的目的主要是為了適配返回類型,其內部會對OkhttpCall對象進行包裝

? ? ? ? ? }

? ? ? ? });

? }

Retrofit的create方法通過動態(tài)代理的模式卿叽,生成了實現(xiàn)了具體的網絡請求接口的對象桥胞,并在InvocationHandler的invoke方法中統(tǒng)一處理網絡請求接口實體對象的方法,invoke方法會通過方法構造一個ServiceMethod對象考婴,并將其放入緩存中贩虾,然后根據(jù)ServiceMethod對象和網絡請求的參數(shù)args去構造一個OkHttpCall對象,最后調用serviceMethod的callAdapter的adapt方法沥阱,傳入將OkHttpCall對象缎罢,callAdapter的目的主要是為了適配OkHttpCall對象,其內部會對OkHttpCall對象進行包裝考杉,生成對應返回類型的對象策精。

動態(tài)代理的原理主要是在運行時動態(tài)生成代理類,然后根據(jù)代理類生成一個代理對象崇棠,在這個代理對象的方法中中又會調用InvocationHandler的invoke來轉發(fā)對方法的處理咽袜,比如,TranslateApi生成的代碼類代碼大致應該如下:

public Class Translate implement Translate {

InvokeHandler mInvokeHandler;

Call<TranslateBean> translateRequest(String input) {

Method translateRequestMethod = Class.forName("packagename.TranslateApi").getMethod("translateRequest", String.class); // 通過反射獲得TranslateApi的translateRequest方法

mInvokeHandler.invoke(this, translateRequestMethod, new Object[] {input}); // 調用InvokeHandler的invoke方法枕稀,并傳入當前對象询刹,方法,方法傳入?yún)?shù)

}

}

代理類的代碼是動態(tài)生成的萎坷,生成代碼后我們就可以用ClassLoader將其加載到內存中凹联,并通過反射生成代理對象,代理類會將方法的處理轉發(fā)給InvokeHandler哆档,所以所有對代理對象方法的調用都會由InvocationHandler的invoke方法處理蔽挠。

3、loadServiceMethod方法

? ServiceMethod<?, ?> loadServiceMethod(Method method) { // 根據(jù)方法返回一個對應的ServiceMethod對象

? ? ServiceMethod<?, ?> result = serviceMethodCache.get(method); // 首先從緩存中獲取

? ? if (result != null) return result;

? ? synchronized (serviceMethodCache) {

? ? ? result = serviceMethodCache.get(method);

? ? ? if (result == null) { // 如果緩存中沒有則構造一個ServiceMethod對象并將其放入緩存中

? ? ? ? result = new ServiceMethod.Builder<>(this, method).build();

? ? ? ? serviceMethodCache.put(method, result);

? ? ? }

? ? }

? ? return result;

? }

loadServiceMethod首先會從緩存中獲取ServiceMethod對象瓜浸,如果沒有澳淑,則通過Method和Retrofit對象構造一個ServiceMethod對象比原,并將其放入緩存中。

4杠巡、ServiceMethod的構造

ServiceMethod其實是用來存儲一次網絡請求的基本信息的春寿,比如Host、URL忽孽、請求方法等,同時ServiceMethod還會存儲用來適配OkHttpCall對象的CallAdpater谢床。ServiceMethod的build方法會解讀傳入的Method兄一,首先ServiceMethod會在CallAdpaterFactory列表中尋找合適的CallAdapter來包裝OkHttpCall對象,這一步主要是根據(jù)Method的返回參數(shù)來匹配的识腿,比如如果方法的返回參數(shù)是Call對象出革,那么ServiceMethod就會使用默認的CallAdpaterFactory來生成CallAdpater,而如果返回對象是RxJava的Obserable對象渡讼,則會使用RxJavaCallAdapterFactory提供的CallAdpater。然后build方法會解讀Method的注解,來獲得注解上配置的網絡請求信息治筒,比如請求方法腹殿、URL、Header等蹬昌。

? ? public ServiceMethod build() {

? ? ? callAdapter = createCallAdapter(); // 查找能夠適配返回類型的CallAdpater

? ? ? responseType = callAdapter.responseType();

? ? ? if (responseType == Response.class || responseType == okhttp3.Response.class) {

? ? ? ? throw methodError("'"

? ? ? ? ? ? + Utils.getRawType(responseType).getName()

? ? ? ? ? ? + "' is not a valid response body type. Did you mean ResponseBody?");

? ? ? }

? ? ? responseConverter = createResponseConverter();

? ? ? // 解讀方法的注解

? ? ? for (Annotation annotation : methodAnnotations) {

? ? ? ? parseMethodAnnotation(annotation);

? ? ? }

? ? ? if (httpMethod == null) {

? ? ? ? throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");

? ? ? }

? ? ? if (!hasBody) {

? ? ? ? if (isMultipart) {

? ? ? ? ? throw methodError(

? ? ? ? ? ? ? "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");

? ? ? ? }

? ? ? ? if (isFormEncoded) {

? ? ? ? ? throw methodError("FormUrlEncoded can only be specified on HTTP methods with "

? ? ? ? ? ? ? + "request body (e.g., @POST).");

? ? ? ? }

? ? ? }

? ? ? int parameterCount = parameterAnnotationsArray.length;

? ? ? parameterHandlers = new ParameterHandler<?>[parameterCount];

? ? ? for (int p = 0; p < parameterCount; p++) {

? ? ? ? Type parameterType = parameterTypes[p];

? ? ? ? if (Utils.hasUnresolvableType(parameterType)) {

? ? ? ? ? throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",

? ? ? ? ? ? ? parameterType);

? ? ? ? }

? ? ? ? Annotation[] parameterAnnotations = parameterAnnotationsArray[p];

? ? ? ? if (parameterAnnotations == null) {

? ? ? ? ? throw parameterError(p, "No Retrofit annotation found.");

? ? ? ? }

? ? ? ? parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);

? ? ? }

? ? ? if (relativeUrl == null && !gotUrl) {

? ? ? ? throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);

? ? ? }

? ? ? if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {

? ? ? ? throw methodError("Non-body HTTP method cannot contain @Body.");

? ? ? }

? ? ? if (isFormEncoded && !gotField) {

? ? ? ? throw methodError("Form-encoded method must contain at least one @Field.");

? ? ? }

? ? ? if (isMultipart && !gotPart) {

? ? ? ? throw methodError("Multipart method must contain at least one @Part.");

? ? ? }

? ? ? return new ServiceMethod<>(this);

? ? }

我們來看一下查找CallAdpater的代碼:

? ? 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 {

? ? ? ? //noinspection unchecked

? ? ? ? return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations); // 調用retrofit的callAdpater方法查找合適的CallAdpater

? ? ? } catch (RuntimeException e) { // Wide exception range because factories are user code.

? ? ? ? throw methodError(e, "Unable to create call adapter for %s", returnType);

? ? ? }

? ? }

可以看到混驰,會調用retrofit的callAdapter去查找合適的CallAdapter,傳入的參數(shù)為方法的返回類型和注解

Retrofit的callAdapter方法:

? public CallAdapter<?, ?> nextCallAdapter(@Nullable 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++) { // 遍歷所有的CallAdpaterFactory皂贩,找到能夠適配的CallAdpater

? ? ? CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);

? ? ? if (adapter != null) {

? ? ? ? return adapter;

? ? ? }

? ? }

? ? ...

? }

Retrofit的CallAdpater方法會遍歷所有的CallAdpaterFactory栖榨,找到能夠適配的CallAdpater,我們首先來看一下默認的CallAdpaterFactory是如何生成CallAdapter的:

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) { // 首先判斷方法的返回類型是不是Call類型明刷,如果不是則說明這個CallAdpaterFactory適配不了

? ? ? return null;

? ? }

? ? final Type responseType = Utils.getCallResponseType(returnType);

? ? return new CallAdapter<Object, Call<?>>() { // 返回CallAdpater

? ? ? @Override public Type responseType() {

? ? ? ? return responseType;

? ? ? }

? ? ? @Override public Call<Object> adapt(Call<Object> call) {

? ? ? ? return call; // 直接將call返回

? ? ? }

? ? };

? }

}

DefaultCallAdapterFactory是默認的CallAdpaterFactory婴栽,它在Retrofit構造時會加入到CallAdapterFactory列表中,可以看到辈末,它只會去適配返回類型為Call的方法愚争。

我們再來看一下返回類型為Observable是如何適配的:

首先,我們在構造Retrofit對象時需要加入適配RxJava返回對象的

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

我們來看一下RxJava2CallAdpaterFactory的get方法:

? @Override

? public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

? ? Class<?> rawType = getRawType(returnType); // 獲得返回類型

? ? if (rawType == Completable.class) { // 如果返回類型為RxJava的Completable類型本冲,則可以適配

? ? ? // Completable is not parameterized (which is what the rest of this method deals with) so it

? ? ? // can only be created with a single configuration.

? ? ? return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,

? ? ? ? ? false, true);

? ? }

? ? boolean isFlowable = rawType == Flowable.class;

? ? boolean isSingle = rawType == Single.class;

? ? boolean isMaybe = rawType == Maybe.class;

? ? // 如果返回類型為RxJava的Flowable准脂、Single、Maybe檬洞、Observable類型狸膏,則可以適配

? ? if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {

? ? ? return null;

? ? }

? ? boolean isResult = false;

? ? boolean isBody = false;

? ? Type responseType;

? ? if (!(returnType instanceof ParameterizedType)) {

? ? ? String name = isFlowable ? "Flowable"

? ? ? ? ? : isSingle ? "Single"

? ? ? ? ? : isMaybe ? "Maybe" : "Observable";

? ? ? throw new IllegalStateException(name + " return type must be parameterized"

? ? ? ? ? + " as " + name + "<Foo> or " + name + "<? extends Foo>");

? ? }

? ? Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);

? ? Class<?> rawObservableType = getRawType(observableType);

? ? if (rawObservableType == Response.class) {

? ? ? if (!(observableType instanceof ParameterizedType)) {

? ? ? ? throw new IllegalStateException("Response must be parameterized"

? ? ? ? ? ? + " as Response<Foo> or Response<? extends Foo>");

? ? ? }

? ? ? responseType = getParameterUpperBound(0, (ParameterizedType) observableType);

? ? } else if (rawObservableType == Result.class) {

? ? ? if (!(observableType instanceof ParameterizedType)) {

? ? ? ? throw new IllegalStateException("Result must be parameterized"

? ? ? ? ? ? + " as Result<Foo> or Result<? extends Foo>");

? ? ? }

? ? ? responseType = getParameterUpperBound(0, (ParameterizedType) observableType);

? ? ? isResult = true;

? ? } else {

? ? ? responseType = observableType;

? ? ? isBody = true;

? ? }

? ? return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,

? ? ? ? isSingle, isMaybe, false);

? }

可以看到,RxJava2CallAdpaterFactory能夠處理返回類型為RxJava的Completable添怔、Flowable湾戳、Single贤旷、Maybe、Observable類型砾脑,并提供一個RxJava2CallAdpater適配器幼驶。

5、根據(jù)ServiceMethod和args生成OkHttpCall對象

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

我們知道韧衣,ServiceMethod封裝了網絡請求的基本信息盅藻,比如Host、URL等畅铭,我們根據(jù)ServiceMethod和請求參數(shù)args就可以確定本次網絡請求的所有信息了氏淑,OkHttpCall主要是將這些信息封裝起來,并調用OkHttp的接口去發(fā)送網絡請求硕噩,這里假残,我們就將OkHttpCall看成是一個處理網絡請求的類即可。

6炉擅、serviceMethod.callAdpater.adpat(okHttpCall)

這一步主要是將能夠處理網絡請求的OkHttpCall對象通過適配器適配成方法返回類型的對象辉懒,以Observable為例,我們知道RxJava和Retrofit結合使用的代碼大致如下:

Observable<DataBean> observable = requestApi.request("xiaoming");

observable.subscribleOn(Sechedulers.io())

? ? ? ? .observerOn(AndroidSecheduler.mainThread())

? ? ? ? .subscrible(new Observer() {

? ? ? ? public void onNext(DataBean dataBean) {

? ? ? ? }

? ? ? ? public void onError(Error e) {

? ? ? ? }

? ? ? ? ...

? ? ? ? })

也就是說我們通過調用接口返回了一個observable(被觀察者)對象谍失,然后給obserable綁定了一個Observer(觀察者)對象眶俩,并且指定了處理的subscrible線程為子線程,處理observer回調的線程為主線程袱贮。

那么RxJava2CallAdapter的adapt方法是如何將一個Call對象適配成Observable對象的呢仿便?

final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {

? @Override public Object adapt(Call<R> call) {

? ? Observable<Response<R>> responseObservable = isAsync

? ? ? ? ? new CallEnqueueObservable<>(call)

? ? ? ? : new CallExecuteObservable<>(call); // 生成自定義的Observable對象,并且其中封裝了進行網絡請求的Call對象

? ? Observable<?> observable;

? ? if (isResult) {

? ? ? observable = new ResultObservable<>(responseObservable);

? ? } else if (isBody) {

? ? ? observable = new BodyObservable<>(responseObservable);

? ? } else {

? ? ? observable = responseObservable;

? ? }

? ? if (scheduler != null) {

? ? ? observable = observable.subscribeOn(scheduler);

? ? }

? ? if (isFlowable) {

? ? ? return observable.toFlowable(BackpressureStrategy.LATEST);

? ? }

? ? if (isSingle) {

? ? ? return observable.singleOrError();

? ? }

? ? if (isMaybe) {

? ? ? return observable.singleElement();

? ? }

? ? if (isCompletable) {

? ? ? return observable.ignoreElements();

? ? }

? ? return observable;

? }

}

主要看第一行代碼:

Observable<Response<R>> responseObservable = isAsync

? ? ? ? ? new CallEnqueueObservable<>(call)

? ? ? ? : new CallExecuteObservable<>(call); // 生成自定義的Observable對象攒巍,并且其中封裝了進行網絡請求的Call對象

這句代碼會將能夠進行網絡請求的Call對象封裝成一個自定義的Observable對象并返回嗽仪,以CallExecuteObservable為例:

final class CallExecuteObservable<T> extends Observable<Response<T>> {

? private final Call<T> originalCall; // 能夠進行網絡請求的Call對象,也就是我們前面說的OkHttpCall對象

? CallExecuteObservable(Call<T> originalCall) {

? ? this.originalCall = originalCall;

? }

? @Override protected void subscribeActual(Observer<? super Response<T>> observer) { // 這個方法會在Observable調用subscribe方法訂閱觀察者時調用

? ? // Since Call is a one-shot type, clone it for each new observer.

? ? Call<T> call = originalCall.clone();

? ? observer.onSubscribe(new CallDisposable(call));

? ? boolean terminated = false;

? ? try {

? ? ? Response<T> response = call.execute(); // 調用OkHttpCall對象柒莉,執(zhí)行網絡請求并獲得響應結果

? ? ? if (!call.isCanceled()) {

? ? ? ? observer.onNext(response); // 調用Obserber的onNext方法闻坚,發(fā)送返回接口

? ? ? }

? ? ? if (!call.isCanceled()) {

? ? ? ? terminated = true;

? ? ? ? observer.onComplete();

? ? ? }

? ? } catch (Throwable t) {

? ? ? Exceptions.throwIfFatal(t);

? ? ? if (terminated) {

? ? ? ? RxJavaPlugins.onError(t);

? ? ? } else if (!call.isCanceled()) {

? ? ? ? try {

? ? ? ? ? observer.onError(t); // 請求出錯則調用Observer的onError方法

? ? ? ? } catch (Throwable inner) {

? ? ? ? ? Exceptions.throwIfFatal(inner);

? ? ? ? ? RxJavaPlugins.onError(new CompositeException(t, inner));

? ? ? ? }

? ? ? }

? ? }

? }

? ...

}

可以看到CallExecuteObserable繼承了Obserable,并重寫了其subscribeActual方法兢孝,subscribeActual會在Obserable對象調用subcrible方法時調用窿凤,在subscribeActual方法中,首先是調用了OkHttpCall的execute()方法發(fā)起網絡請求跨蟹,并獲得網絡請求結果雳殊,如果請求成功,會調用Observer的onNext方法窗轩,并將請求結果傳遞給onNext方法夯秃,所以我們可以在Observer的onNext方法種處理網絡請求成功的情況,而如果網絡請求失敗,則會調用Observer的onError方法仓洼。由上介陶,我們知道,CallAdapter的作用是將OkHttpCall對象適配成方法的返回類型的對象色建。

至此哺呜,我們知道了Retrofit的原理,它內部通過動態(tài)代理生成接口的實體對象箕戳,然后通過解讀注解來獲得接口中定義的請求信息某残,通過CallAdapterFactory將OkHttpCall對象適配成接口中定義的返回類型,通過ConverFactory來解讀數(shù)據(jù)陵吸,其底層真正處理網絡請求的還是OkHttp框架(OkHttpCall通過調用OkHttp框架提供的Api處理網絡請求)驾锰。

四、總結

Retrofit是一款能夠將Java接口轉換成一個能夠進行網絡請求對象的框架走越,具有使用簡單,可擴展性強等優(yōu)點耻瑟,其內部通過動態(tài)代理模式生成接口的實體對象旨指,并且在InvocationHandler中統(tǒng)一處理請求方法,通過解讀方法的注解來獲得接口中配置的網絡請求信息喳整,并將網絡請求信息和請求參數(shù)一起封裝成一個OkHttpCall對象谆构,這個OkHttpCall對象內部通過OkHttp提供的Api來處理網絡請求,為了將OkHttpCall對象適配成方法的返回類型框都,Retrofit提供了配置CallAdpaterFactory的Api搬素,比如RxJava2CallAdapterFactory就會將OkHttpCall對象適配成一個Observable對象,并在Obserable的subscribleActual方法中調用OkHttpCall對象發(fā)起網絡請求并回調Observser的onNext方法來處理網絡請求返回的數(shù)據(jù)魏保。Retrofit還提供了配置數(shù)據(jù)格式轉換的API熬尺,可以針對不同的數(shù)據(jù)類型進行處理。

反觀一下Retrofit谓罗,其內部的設計結構非常清晰粱哼,通過動態(tài)代理來處理接口,通過OkHttp來處理網絡請求檩咱,通過CallAdapterFactory來適配OkHttpCall揭措,通過ConverterFactory來處理數(shù)據(jù)格式的轉換,這符合面對對象設計思想的單一職責原則刻蚯,同時绊含,Retrofit對CallAdpaterFactory和ConverterFactory的依賴都是依賴其接口的,這就讓我們可以非常方便的擴展自己的CallAdpaterFactory和ConverterFactory炊汹,這符合依賴倒置原則躬充;不管Retrofit內部的實現(xiàn)如何復雜,比如動態(tài)代理的實現(xiàn)、針對注解的處理以及尋找合適的適配器等麻裳,Retrofit對開發(fā)者隱藏了這些實現(xiàn)細節(jié)口蝠,只提供了簡單的Api給開發(fā)者調用,開發(fā)者只需要關注通過的Api即可實現(xiàn)網絡請求津坑,這種對外隱藏具體的實現(xiàn)細節(jié)的思想符合迪米特原則妙蔗。另外,Retrofit內部大量使用了設計模式疆瑰,比如構造Retrofit對象時使用了Builder模式眉反,處理接口時是用來動態(tài)代理模式,適配OkHttpCall時使用了Adapter模式穆役,生成CallAdpater和Converter時使用了工廠模式寸五。Retrofit的設計正是因為遵循了面向對象的思想,以及對設計模式的正確應用耿币,才使得其具備結構清晰梳杏、易于擴展的特點。

————————————————

版權聲明:本文為CSDN博主「xiao_nian」的原創(chuàng)文章淹接,遵循 CC 4.0 BY-SA 版權協(xié)議十性,轉載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/xiao_nian/article/details/87802483

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末塑悼,一起剝皮案震驚了整個濱河市劲适,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌厢蒜,老刑警劉巖霞势,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愕贡,居然都是意外死亡,警方通過查閱死者的電腦和手機巷屿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門颂鸿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人攒庵,你說我怎么就攤上這事嘴纺。” “怎么了浓冒?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵栽渴,是天一觀的道長。 經常有香客問我稳懒,道長闲擦,這世上最難降的妖魔是什么慢味? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮墅冷,結果婚禮上纯路,老公的妹妹穿的比我還像新娘。我一直安慰自己寞忿,他們只是感情好驰唬,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腔彰,像睡著了一般叫编。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上霹抛,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天搓逾,我揣著相機與錄音,去河邊找鬼杯拐。 笑死霞篡,一個胖子當著我的面吹牛,可吹牛的內容都是我干的端逼。 我是一名探鬼主播寇损,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裳食!你這毒婦竟也來了?” 一聲冷哼從身側響起芙沥,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤诲祸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后而昨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體救氯,經...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年歌憨,在試婚紗的時候發(fā)現(xiàn)自己被綠了着憨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡务嫡,死狀恐怖甲抖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情心铃,我是刑警寧澤准谚,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站去扣,受9級特大地震影響柱衔,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一唆铐、第九天 我趴在偏房一處隱蔽的房頂上張望哲戚。 院中可真熱鬧,春花似錦艾岂、人聲如沸顺少。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽祈纯。三九已至,卻和暖如春叼耙,著一層夾襖步出監(jiān)牢的瞬間腕窥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工筛婉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留簇爆,地道東北人。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓爽撒,卻偏偏與公主長得像入蛆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子硕勿,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內容