【版權申明】非商業目的註明出處可自由轉載
博文地址:
出自:shusheng007
系列文章
秒懂的Retrofit2源碼詳解
用Retrofit+RxJava2封裝優雅的網絡請求框架
秒懂Retrofit2之Converter
秒懂Retrofit2之GsonConverter
概述
Retrofit2 已經成爲Android開發網絡請求當之無愧的扛把子了,我們很有必要對自己經常使用的東西有個深入的瞭解。
Retrofit2 中有兩個非常精彩的設計:Converter 與CallAdapter, 通過這兩個接口,Retrofit的可擴展性被極大的增強了,用戶可以根據需求自由擴展。在上一篇文章 秒懂Retrofit2之Converter中我們對Converter做了比較詳細的解析,這篇文章就對Calladapter做一個比較深入的瞭解。
作用
Retrofit2 中有兩個非常精彩的設計:Converter 與CallAdapter, 這是兩個接口,通過這兩個接口,retrofit的可擴展性被極大的增強了,用戶可以根據需求自由擴展。
假如有如下代碼:其中User
和 Person
是兩個自定義類
@POST
Observable<List<User>>m1(@Body Person rBody);
@POST
Call<List<User>>m2(@Body Person rBody);
仔細觀察方法m1和m2發現他們的返回類型有一定的區別,m1 的放回類型是Rxjava2 的 Observable<T>
而m2是Retrofit2 的Call<T>
。這個類型就是由CallAdapter
決定的,例如Call<T>
類型就是通過CallAdapter
將得到的。Retrofit2 的方法的返回值必須是泛型類型,例如Call<T>
,通過調用CallAdapter
裏的 adapt()
方法,將方法的返回值適配爲類似Call<T>
的樣子,而在這個過程中又調用了Converter
的responseBodyConverter()
方法,將htpp返回的ResponseBody
類型的數據轉換爲Call<T>
裏面的 T
。
源碼解析
我們先看一下CallAdapter
的源碼:
public interface CallAdapter<R, T> {
//retrofit 方法的返回類型的泛型參數代表的類型,例如 方法的返回類型(returnType)爲Call<User> ,那麼responseType 爲User
Type responseType();
//Returns an instance of {@code T} which delegates to {@code call}.
T adapt(Call<R> call);
abstract class Factory {
//獲得一個call adapter
//returnType 爲接口中方法的泛型返回類型例如 Call<User>
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);
//兩個工具方法
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
接口很簡單,裏面僅有兩個方法,responseType()
和adapt()
.
responseType()
是一個取值方法,使用它獲得當前方法的響應類型。主要用途是檢查我們定義的方法返回值裏面那個泛型參數的類型是否正確,例如Call<User>
是正確的,而Call<okhttp3.Response>
則是不正確的。
adapt()
負責適配
接口裏面還有一個內部類Factory
,我們就是通過這個factory
裏的get
方法獲得相應的Adapter的
使用機制
那麼CallAdapter
在retrofit2中是如何發揮作用的呢,關鍵代碼在HttpServiceMethod<ResponseT, ReturnT>
類中的invoke()
方法中,程序每發起一個HTTP請求時,首先就會調用這個方法:
//提交一個http請求,返回我們設定的類型的結果,例如Call<User>
@Override ReturnT invoke(@Nullable Object[] args) {
return callAdapter.adapt(
new OkHttpCall<ResponseT>(requestFactory, args, callFactory, responseConverter));
}
Retrofit2的方法之所以可以返回Call<T>
是因爲其有兩個默認的CallAdapter
實現,DefaultCallAdapterFactory
和ExecutorCallAdapterFactory
, Retrofit2 會自動判斷當前運行的平臺,如果發現是Android平臺則使用ExecutorCallAdapterFactory
,其他情況使用另一個。
DefaultCallAdapterFactory
DefaultCallAdapterFactory 源碼如下:
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) {
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 call;
}
};
}
}
代碼很簡單,通過get獲得一個CallAdapter。首先要求方法的返回值returnType
的原始類型必須是Call
類型,就是說returnType必須爲Call<T>
,然後返回一個Call<Object>
數據。
這就決定了你聲明方法時候必須是如下的形式:
@POST
Call<List<User>>m2(@Body Person rBody);
返回值類型必須是Call<Object>
的形式,你說你想返回Rxjava2的Observerable,別鬧,這個CallAdapter不認識這個東東。
ExecutorCallAdapterFactory
其實ExecutorCallAdapterFactory 應該是做Android開發的重點關注的,其與DefaultCallAdapterFactory 是一脈相承的,唯一的增強就是通過一個MainThreadExecutor 將結果回調切換到了UI線程上,讓我們可以直接在結果回調中操作UI控件。
以下是MainThreadExecutor
的源碼,是不是有一種熟悉的味道
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
ExecutorCallAdapterFactory 的源碼如下:
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@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);
}
});
}
});
}
...
}
}
從上面的源碼中可以看到DefaultCallAdapterFactory
和ExecutorCallAdapterFactory
唯一的區別就是在adapt()
方法中返回的那個Call接口的實現類實例不一樣。
//DefaultCallAdapterFactory 裏的實現方式
@Override public Call<Object> adapt(Call<Object> call) {
return call;
}
//ExecutorCallAdapterFactory 裏的實現方式
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
我們就是在ExecutorCallbackCall 裏面將結果回調切換到了UI線程。
理解了原理後,自定義一個CallAdapter就變的很容易了。 我們使用比較多的就是與Rxjava2結合的RxJava2CallAdapterFactory
, 這個自定義的CallAdapter算是比較複雜的了,那是因爲Rxjava2比較難於上手,其實實現原理還是那一套。就是不返回Call<T>
, 轉而返回Rxjava2自己的類,例如Onserverable<T>
.
總結
可見一個設計優良的類庫,會給用戶很大的擴展空間,這一點我們應該多加學習。
最後,求關注,求點贊!有任何疑問可以評論留言,我會盡力回覆的