一远搪、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