一概述
上一節分析了retrofit2從創建到執行的完整流程,本節分析一下兩個非常重要的功能。數據轉換器的實現以及網絡請求適配器的實現。
二、GsonConvertFactory.create()數據轉換器的實現過程以及執行過程
我們先看下GsonConvertFactory.crete()的源代碼,此類在retrofit-converters插件中
public final class GsonConverterFactory extends Converter.Factory {
//創建GsonConverterFactory對象
public static GsonConverterFactory create() {
return create(new Gson());
}
@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
public static GsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson) {
this.gson = gson;
}
//將請求結果的body進行轉換
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
//這里的TypeAdapter是Gson中用來做序列化和反序列化用的
//其中TypeToken.get(type)是用來獲取一個類類型
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//最后返回一個jsonResponse對象做解析工作
return new GsonResponseBodyConverter<>(gson, adapter);
}
//轉換請求結果的body
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
我們看一下GsonResponseBodyConverter的源代碼,看看其都干了什么事情。
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
//這里的convert方法是Converter接口中定義的convert
@Override public T convert(ResponseBody value) throws IOException {
//創建一個JsonReader對象,jsonReader是gson中的類供TypeAdapter序列化以及反序列化時使用的。
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
//通過TypeAdapter把讀取到的對象轉換為泛型
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
//並把泛型結果返回
return result;
} finally {
value.close();
}
}
}
看下GsonRequestBodyConverter類
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
//實現Converter接口的convert方法
@Override public RequestBody convert(T value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
//創建一個jsonwriter
JsonWriter jsonWriter = gson.newJsonWriter(writer);
//把http請求信息進行序列化
adapter.write(jsonWriter, value);
jsonWriter.close();
//然后把序列化后的結果放到RequestBody中
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
看下Converter.Factroy的源代碼,Converter是一個接口,Factory是其內部抽象類。其中定義了各種類型轉換的接口。
//數據轉換接口
public interface Converter<F, T> {
//數據轉換接口
@Nullable T convert(F value) throws IOException;
/** Creates {@link Converter} instances based on a type and target usage. */
abstract class Factory {
//轉換網絡請求的返回結果
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
//轉換請求結果
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
具體的轉化代碼也就這么多,都是操作Gson的一系列方法實現的。下面看看GsonConvertFactory是如何在框架中調用的。
首先要明確一點,既然是響結果轉換器,其必定是響應結果前實現回調的,即在Callback回調函數前需要把響應結果給轉換后再給Callback。
上一節我們說過我們生成的Call其實就是DefaultCallAdapterFactory中的ExecutorCallbackCall。然而ExecutorCallbackCall中卻沒有看得到Converter的身影。ExecutorCallbackCall的源碼如下:
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) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(() -> {
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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
那么接着往上一級目錄找找,我們記得在HttpMethodService類的內部有一個invoke方法,其會調用他的實現類CallAdapted類的adapt方法,方法內部會調用DefaultCallAdapterFactory的adapt方法並返回一個ExecutorCallbackCall。並傳入一個Call和方法的參數。這個Call的實現類就是HttpCall。你沒看錯響應結果轉換就發生在這個類中。
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
既然已經確定了響應數據轉換在HttpCall中發生。那我們看下他具體做了什么事情。
final class OkHttpCall<T> implements Call<T> {
private final RequestFactory requestFactory;
private final Object[] args;
private final okhttp3.Call.Factory callFactory;
private final Converter<ResponseBody, T> responseConverter;
private volatile boolean canceled;
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
@GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException.
private @Nullable Throwable creationFailure;
@GuardedBy("this")
private boolean executed;
OkHttpCall(RequestFactory requestFactory, Object[] args,
okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) {
this.requestFactory = requestFactory;
this.args = args;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
}
果然如上面我們分析的那樣,HttpCall接收了一個Converter<ResponseBody,T> responseConverter變量。而這個變量就是我們創建retrofit設置的GsonConvertFactory.create()。
在HttpCall的內部有一個enqueue(callback)方法,其內部會調用parseResponse方法。parseResponse內部會調用convert方法對數據進行轉換。這個convert方法就是上面我們提到的GsonResponseBodyConvert。
HttpCall的enqueue方法
@Override public void enqueue(final Callback<T> callback) {
...省略了前面的一些代碼
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
....省略了一些代碼
});
}
接下來看下parseResponse方法
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
...省略了一些diamante
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//在此處做轉換操作,這里的responseConverter就是GsonResponseBodyConverter
T body = responseConverter.convert(catchingBody);
//把body設置進去
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
到這里轉換操作就完成了,converter方法的具體實現可以參考上面的GsonResponseBodyConverter源碼。
總結:通過Retrofit設置響應數據轉換器GsonConvertFactory.create(),在HttpCall中的enqueue方法中的parseResponse做具體的轉換,轉換調用的是responseConverter.convert(catchingBody)。其中responseConverter的具體轉換操作是在GsonResponseBodyConverter中完成的。好了GsonConvertFactory.create()的源碼以及執行流程就這樣分析完了。
ps:補充一下自定義響應數據解析器
根據上面的分析我們知道創建響應數據解析器的時候解析器需要繼承Converter.Factory,並實現Converter.Factory的responseBodyConverter接口。那么我們在自定義響應數據解析器的時候也可以這么干。三部搞定
1.創建一個XmlConverterFactory並繼承Converter.Factory的並實現其responseBodyConverter方法
2.創建一個具體的解析類,並當做responseBodyConverter的返回值
3.在retrofit的Builder中注解解析器XmlConverterFactory.create()
下面是以上三步的示例代碼:
/**
* xml響應數據解析器
* create by yangwei
* on 2020-02-25 20:12
*/
public class XmlConverterFactory extends Converter.Factory {
public static XmlConverterFactory create() {
return new XmlConverterFactory(new Xml());
}
public static XmlConverterFactory create(Xml xml) {
return new XmlConverterFactory(xml);
}
@javax.annotation.Nullable
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new XmlResponseBodyFactory();
}
}
/**
* create by yangwei
* on 2020-02-25 20:16
*/
public class XmlResponseBodyFactory implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
@javax.annotation.Nullable
@Override
public RequestBody convert(T value) throws IOException {
//此處做具體轉換操作
return RequestBody.create(MEDIA_TYPE,value.bytes);
}
}
在Retrofit的Builder中設置其網絡請求數據轉換器
Retrofit retrofit = new Retrofit.Builder().
baseUrl("http://www.xxxx.com/").//請求地址
addConverterFactory(XmlConverterFactory.create()).//自定義xml網絡請求結果轉換器
addCallAdapterFactory(RxJava2CallAdapterFactory.create()).//網絡請求適配器
build();
自定義的示例代碼就寫完了,大家在實際的開發過程中可以根據需要自行添加自定義網絡請求結果轉換器,或者對轉換器進行修正。
三、RxJava2CallAdapterFactory.create()網絡請求適配器的實現過程以及執行過程
上一節分下了默認的請求網絡適配器DefaultCallAdapterFactory。讓我們先來回顧下它具體是如何工作的。
首先在retrofit的builder中進行設置,不設置也行默認就是使用的DefaultCallAdapterFactory請求網絡適配器。
在上一節中我們通過retrofit的create方法動態生成了一個接口實例,並調用接口實例的方法返回了一個Call,生成過程是調用loadServiceMethod.invoke(map)方法,ServiceMethod是個抽象類, 其實現類是HttpServiceMethod,在HttpServiceMethod中重新會真正的調用invoke方法,並實例化一個OkHttpCall,通過其HttpServiceMethod的invoke方法,在其方法內部會調用DefaultCallAdapterFactory.adapt方法,DefaultCallAdapterFactory的adapt方法會生成一個ExecutorCallbackCall並返回。
下面說說RxJava2CallAdapterFactory網絡請求適配器是如何實現的,其實原理和前面說的也是差不多的,至少前半部分是相同的。
先用文本描述一下流程,然后后面說源碼的時候就比較清晰了:
1.在創建Retrofit的時候添加網絡請求適配器,即添加RxJava2CallAdapterFactory的能力。
2.然后在retrofit的中有一個callAdapter方法,其內部會調用nextCallAdapter方法,通過網絡適配器工廠集合callAdapterFactories.get(i).get(returntype,annotations,this)方法返回一個適配器,.get(i)方法返回的這個適配器就是我們設置的RxJava2CallAdapterFactory,后面的get(retrunType,annotations,this)方法返回的則是集成CallAdapter接口的RxJava2CallAdapter類。
3.接着會調用Retrofit的create中的代理方法loadServiceMethod的invoke方法。invoke方法最終是在HttpServiceMethod方法中執行的,並且invoke方法會調用RxJava2CallAdapterFactory中的adapt方法,並傳入一個OkHttpCall。在adapt的內部會根據同步調用或者異步調用返回一個ResultObservable的被觀察者,ResultObservable里面封裝了CallEnqueueObservable或者CallExecuteObservable,而以上兩個Observable又封裝了OkHttpCall,所以ResultObservable間接持有了OkHttpCall,到此我們需要的Observable也就生成了,其生成步驟可以簡化為:retrofit.create->loadServiceMethod.invoke->ServiceMethod.invoke->HttpServiceMethod.invoke->RxJava2CallAdapterFactory.adapt->ResultObservable。
4.執行過程,當ResultObservable調用其subscribe方法的時候最終會調用其subscribeActual方法,在其subscribeActual內部會調用CallEnqueueObservable的subscribe方法並把ResultObserver當做參數傳遞過去。在CallEnqueueObservable的subscribe方法中又會調用其自身的subscribeActual方法實現觀察者與被觀察者的最終綁定,並且會創建一個CallCallback對象,並調用OkHttpCall的enqueue方法執行網絡請求,參數就是剛剛創建的CallBbackCall,其持有observer的引用和OkHttpCall的引用。在OkHttpCall的enqueu方法內部會調用網絡請求真正的Call(okhttp3.Call)的enqueue方法發起真正的網絡請求,並將網絡請求的執行結果寫入剛剛傳進來的CallBackCall的onResponse方法。而CallBackCall的onResponse方法又會回調ResultObservable的onNext方法,而ResultObservable的onNext方法又會調用LambdaObserver的onNext方法,LambdaObserver.onNext方法會最終調用觀察這個的回調接口,從而完成整個調用過程。
a.添加適配器
addCallAdapterFactory(RxJava2CallAdapterFactory.create()).//網絡請求適配器
b.retrofit中返回CallAdaper網絡適配器
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
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;
}
}
c.創建ResultObservable
HttpServiceMethod中調用invoke方法,並執行RxJava2CallAdapter.adapt(OkHttpCall)
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
//返回ResultObservable
return callAdapter.adapt(call);
}
}
以上callAdapter的真正實現是RxJava2CallAdapter,所以我們直接看它的代碼
@Override public Object adapt(Call<R> call) {
//根據同步或者異步創建Observable
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
//把創建好的Observable包裝秤ResultObservable
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
到此處ResultObservable已經創建完成了,下面看看其是怎樣執行的
d.執行過程
執行過程的開始會調動ResultObservable的subscribe對觀察者和被觀察者進行綁定,其最終會只執行ResultObservable的subscribeActual方法
@Override protected void subscribeActual(Observer<? super Result<T>> observer) {
upstream.subscribe(new ResultObserver<T>(observer));
}
從這段代碼中我們可以看穿其僅僅執行了訂閱而已,其中upstream指的是CallEnqueuObservable或者CallExecuteObservable,這里的參數中的Observer指的是LambdaObserver。
我們看下ResultObserver都干了些啥,主要看onNext方法
private static class ResultObserver<R> implements Observer<Response<R>> {
private final Observer<? super Result<R>> observer;
ResultObserver(Observer<? super Result<R>> observer) {
this.observer = observer;
}
@Override public void onSubscribe(Disposable disposable) {
observer.onSubscribe(disposable);
}
@Override public void onNext(Response<R> response) {
observer.onNext(Result.response(response));
}
在onNext方法中僅僅是調用了LambdaObserver的onNext方法而已。
回過頭來看EnQueueObservable的subscribe,由於subscribe最終會調用subscribeActual方法,所以我們直接看其這個方法就行了
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
//這里的Call指的是OkHttpCall
Call<T> call = originalCall.clone();
//創建一個CallCallback會回調類,並將網絡請求call和ResultObserver傳遞進去
CallCallback<T> callback = new CallCallback<>(call, observer);
//綁定
observer.onSubscribe(callback);
if (!callback.isDisposed()) {
//執行OkHttpCall的enqueue方法並把CallCallbac實例傳遞進去
call.enqueue(callback);
}
}
我們接着看OkHttpCall的enqueue都干了些啥
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
...省略了一些代碼
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
...省略了下面的代碼
}
這個方法非常的明確,其利用okhttp3的Call的enqueu發起真正的網絡請求並把回調結果寫入CallCallback中的onResponse中。
在CallCallback的onResponse方法中會調用ResultObserver的onNext方法,並把響應就結果傳入
@Override public void onResponse(Call<T> call, Response<T> response) {
if (disposed) return;
try {
observer.onNext(response);
緊接着ResultObserver的onNext方法又會調用LambdaObserver的onNext方法並傳入響應結果,再接着LambdaObserver的onNext方法又會調用觀察者設置的回調函數。到此為止整個執行過程就已經結束了。
ps:自定義網絡請求適配器的方法和數據轉換器的步驟類似,這里簡單說一下
1.首選定義一個繼承自CallAdapter.Factory的類並實現其方法,在其方法中返回真正適配的類,即實現了CallAdapter接口的類。
2.定義一個實現了CallAdapter接口的類,在這個中完成真正的適配
3.在創建retrofit的時候在其Builder中設置這個適配器即可。
四、總結
經過分析GsonConverterFactory和RxJava2CallAdapterFactory相信大家對retrofit的理解又有一些更深的感悟了,實時求實的說多讀讀開源代碼對技能和內功的修煉是非常有幫助的。
