前提
只有瞭解了框架的原理才能更好的使用她,才能定位問題的根本。寫這篇文章的也是為了自我的學習和提升。其實看原始碼就跟看書一樣,看了這麼多本書有什麼用呢,其實不然,這些知識已經潛移默化的影響了你的思維。你之後在閱讀原始碼時,會發現能更快的上手了。
引用別人的一句話:當我還是個孩子時吃的很多食物,大部分已經一去不復返而且被我忘掉了,但可以肯定的是,它們中的一部分已經長成我的骨頭和肉
友情提醒
1.這篇文章主要講retrofit如何request 和 response
2.不會詳細到每個api
3.文章會以一個flow 來講解
上圖
如果下圖有錯誤歡迎評論指正,如果看不清你可以下載下來放大看,應該會好點。我們這次會以這個圖的flow 來講解(主要是左半邊)。
retrofit初始化配置
這裡講解的就是上圖中的adapterFactories,我們們這邊以RxjavaAdapter來講解,下面是一些retrofit的初始化配置。
private Retrofit createRetrofit(OkHttpClient client, String url) {
return new Retrofit.Builder()
.baseUrl(url)
.client(client)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
}複製程式碼
這裡我們只說一下主要的東西,大家都知道retrofit的adapter 我們根據我們api請求的不同設定不同的adapter來讓retrofit執行不同的操作,當我們在設定他的CallAdapter時,點進原始碼可以看到,retrofit把這個CallAdapter存入了一個集合中
final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();複製程式碼
然後通過build把這個集合回傳給了retrofit的這個全域性邊變數List<CallAdapter.Factory> adapterFactories
儲存著這些CallAdapter,仔細看的同學會發現,retrofit會預設給你新增一個CallAdapter
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//這裡就是預設的adapter 防止使用者未設定。
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);
}
}複製程式碼
以上就說到這裡,知道有個CallAdapterFactory集合存在Retrofit的全域性變數中。
配置Api
這裡講解的是圖中的這方法
create(final Class<T> service)
稍微提一下吧。上面的adapter其實是根據你在Api中配置的返回引數有關。當我們要使用Rxjava時我們傳對應的Rxjava的adapter 如果我們配置的是okhttp的Call回撥,自然我們都不需要配置adapter,retrofit都給我們預設配置好了,下圖可以看到兩種不同的response
public interface Api {
@Multipart
@POST("upload")
Observable<BaseBean> postVoice(@Part("deviceNo") RequestBody deviceNo,
@Part("duration") RequestBody duration,
@Part("title") RequestBody title,
@Part MultipartBody.Part file);
@GET("selfList")
Call<VoiceList> getVoiceList(@Query("deviceNo")String deviceNo);
}複製程式碼
Request
這裡講解的是上圖中的
create(final Class<T> service)
和ServiceMethod
當我們要發起請求的時候,我們是不是這樣做,拿到之前配置好的Retrofit然後呼叫他的Create方法然後把相應的api傳入.Retroift.create(Api.class)
這樣的操作
現在我們進入原始碼檢視這個retrofit最亮點的地方(create(api.class)),通過反射例項化介面,然後攔截介面中的方法,來做api的請求。返回給這個method。
先把原始碼晾上然後講解
public <T> T create(final Class<T> service) {
·······省略的程式碼·······
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
·······省略的程式碼·······
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}複製程式碼
上面的程式碼已經是把無關緊要的程式碼剔除了,我們只看重要的程式碼
- 我們可以看到create這個方法通過代理反射例項化我們傳進來的api介面
- 然後通過
ServiceMethod
和OkHttpCall
來拿到這個方法的相關引數,來invoke這個方法 - 最後通過
serviceMethod.callAdapter.adapt(okHttpCall)
把請求到的值返回回去
其實在最後一步大家應該明白了,請求是來自於ServiceMethod的callAdapter引數,然後通過adapt來進行okhttp請求。
下面我會講解這個calladapter 如何而來。
ServiceMethod如何發起請求
這是一個流程哈,我們這時候進入程式碼core部分,他的ServiceMethod時通過retrofit的loadServiceMethod拿到的例項化物件。我們進入這個方法可以看到其實這是一個全域性的ServiceMethod的cacheMap
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}複製程式碼
但是不論他做不做快取肯定有new 的地方,然後才能加入快取中吧。從上圖程式碼中我們可以看到這個new 的地方。
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}複製程式碼
這下清楚了ServiceMethod哪裡來的了吧,通過new ServiceMethod.Builder<>(this, method).build()
這句話來的。看原始碼不都這樣嗎!一步一步的進入原始碼然後理解他的每一層 意思和目的。to be continue
上ServiceMethod.Builder的原始碼,我們只看重要的程式碼,其他的忽略
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
·······省略的程式碼·······
}複製程式碼
小夥子們,是不是看到了我們一直最關心的calladapter了,在build的時候通過createCallAdapter來初始化了這個值。進入方法看個究竟
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
·······省略的程式碼·······
Annotation[] annotations = method.getAnnotations();
try {
····敲黑板,敲黑板,敲黑板·····
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}複製程式碼
看到了吧,小夥伴這個calladapter 來自於retrofit裡面的方法,我們在loadServiceMethod的時候還記得這句程式碼嗎?new ServiceMethod.Builder<>(this, method).build()
我們把retrofit傳了進來,然後這裡通過retrofit的callAdapter來獲取ServiceMethod的adapter。下面是retrofit的原始碼獲取c
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}複製程式碼
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
·······省略的程式碼·······
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
·······省略的程式碼·······
}複製程式碼
我感覺只要不眼瞎都能看到這個serviceMethod的calladapter 是來自於我們retrofit之前進行初始化配置時候的RxJavaCallAdapterFactory.create()
其實我們可以在之前的圖中看到這個flow,.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
最終指向的是ServiceMethod的CallAdapter。
進入RxJavaCallAdapterFactory
的原始碼吧。其實這裡的程式碼並不多,只不過有些雜亂。下面我會把不需要的程式碼過濾
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
/**
* Returns an instance which creates synchronous observables that do not operate on any scheduler
* by default.
*/
public static RxJavaCallAdapterFactory create() {
return new RxJavaCallAdapterFactory(null, false);
}
/**
* Returns an instance which creates asynchronous observables. Applying
* {@link Observable#subscribeOn} has no effect on stream types created by this factory.
*/
public static RxJavaCallAdapterFactory createAsync() {
return new RxJavaCallAdapterFactory(null, true);
}
/**
* Returns an instance which creates synchronous observables that
* {@linkplain Observable#subscribeOn(Scheduler) subscribe on} {@code scheduler} by default.
*/
@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
public static RxJavaCallAdapterFactory createWithScheduler(Scheduler scheduler) {
if (scheduler == null) throw new NullPointerException("scheduler == null");
return new RxJavaCallAdapterFactory(scheduler, false);
}
private final @Nullable Scheduler scheduler;
private final boolean isAsync;
private RxJavaCallAdapterFactory(@Nullable Scheduler scheduler, boolean isAsync) {
this.scheduler = scheduler;
this.isAsync = isAsync;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
·······省略的程式碼·······
if (isCompletable) {
return new RxJavaCallAdapter(Void.class, scheduler, isAsync, false, true, false, true);
}
·······省略的程式碼·······
return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
false);
}
}複製程式碼
可以看到這個RxJavaCallAdapterFactory繼承了CallAdapter.Factory,實現了他的get方法,在get方法中我們就可以拿到這個CallAdapter,然後進行我們的adapt方法請求。
從上面的程式碼可以看到真正實現CallAdapter的是RxJavaCallAdapter
我們繼續看看這個RxJavaCallAdapter到底幹了什麼!!!同樣我會過濾不需要的程式碼
final class RxJavaCallAdapter<R> implements CallAdapter<R, Object> {
·······省略的程式碼·······
@Override public Object adapt(Call<R> call) {
OnSubscribe<Response<R>> callFunc = isAsync
? new CallEnqueueOnSubscribe<>(call)
: new CallExecuteOnSubscribe<>(call);
OnSubscribe<?> func;
if (isResult) {
func = new ResultOnSubscribe<>(callFunc);
} else if (isBody) {
func = new BodyOnSubscribe<>(callFunc);
} else {
func = callFunc;
}
Observable<?> observable = Observable.create(func);
·······省略的程式碼·······
return observable;
}
}複製程式碼
好了,這下清晰了許多_這個RxJavaCallAdapter實現了CallAdapter的adapt請求。然後在adapt中需要傳入引數就是Call 然而我們可以回到圖中看到,OkHttpCall正好是Call的實現類。這裡就是上圖中的右邊部分。_
可以在這個方法中看到了,同步非同步請求對應的不一樣的然後呼叫不同的CallEnqueueOnSubscribe,CallExecuteOnSubscribe進行request
進入CallEnqueueOnSubscribe
原始碼看看
final class CallEnqueueOnSubscribe<T> implements OnSubscribe<Response<T>> {
private final Call<T> originalCall;
CallEnqueueOnSubscribe(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override public void call(Subscriber<? super Response<T>> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
Call<T> call = originalCall.clone();
final CallArbiter<T> arbiter = new CallArbiter<>(call, subscriber);
subscriber.add(arbiter);
subscriber.setProducer(arbiter);
call.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, Response<T> response) {
arbiter.emitResponse(response);
}
@Override public void onFailure(Call<T> call, Throwable t) {
Exceptions.throwIfFatal(t);
arbiter.emitError(t);
}
});
}
}複製程式碼
看到了吧這裡終於發起請求了可以看到,執行了OkHttpCall.enqueue請求,同時通過arbiter.emitResponse(response);
把引數回撥了回來。
這就是retrofit的請求flow。
思路整理
- 配置retrofit(addCallAdapterFactory)
- 建立ApiService
- 通過retrofit的create例項化ApiService介面
- 建立ServiceMethod
- 通過retrofit的AdapterFactories拿到ServiceMethod的CallAdapter
- 建立OkHttpCall請求工具類
- 通過ServiceMethod的CallAdapter的adapt進行請求並把第六步寫好的call當引數傳給adapt。
- 把ServiceMethod請求回來的引數返回給對應的ApiService裡面的方法
- 請求完成
ending
嘿嘿嘿,小夥伴們上面有什麼錯誤的話或者不懂得都可以在留言中提及了,小編會在看到的第一時間響應。
To Be Continued