咱們先來看一下Retrofit的常見使用方法:git
//建立網絡請求接口類
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
//建立Retrofit實例對象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
//經過動態代理建立網絡接口代理對象
GitHubService service = retrofit.create(GitHubService.class);
//獲取Call對象
Call<List<Repo>> repos = service.listRepos("octocat");
//執行同步請求或異步請求
repos.execute();
repos.enqueue(callback)
複製代碼
上面是Retrofit的最基本使用方法,固然如今使用最多的仍是RxJava2+Retrofit搭配使用,關於RxJava2,你們能夠看個人另外一篇 RxJava2源碼分析 ,固然RxJava2與Retrofit搭配使用的解析我會在稍後分析,這裏咱們先關注最基本的使用方法。github
這一步的目的就是封裝咱們網絡請求相關的一些參數,沒什麼好多說的。設計模式
Retrofit實例對象的建立很明顯是採用了Builder模式,Builder模式在 Java語言中 建立一個 有不少可選配置參數 的對象的時候是很好的一種設計模式。Builder模式有兩個重點,一個是在 Java語言中 中,另外一個是 有不少可選配置參數,其實在如今的Android開發中,使用Kotlin開發Android已經很廣泛了,熟悉Kotlin語法的小夥伴可能很熟悉了,因爲Kotlin中 默認參數 的存在,因此在Kotlin中使用Builder模式的意義不大。但因爲Java語法的限制,在建立一個 有不少可選配置參數 的時候,Builder模式仍是首要選擇。api
咱們來看一下Retrofit中的成員變量:緩存
public final class Retrofit {
//緩存封裝好的ServiceMethod
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
//OKHttp中的網絡請求工廠
final okhttp3.Call.Factory callFactory;
//BaseUrl
final HttpUrl baseUrl;
//數據轉換器工廠集合
final List<Converter.Factory> converterFactories;
//網絡請求適配器工廠集合
final List<CallAdapter.Factory> callAdapterFactories;
//處理線程切換
final @Nullable Executor callbackExecutor;
//不須要關注,默認爲false
final boolean validateEagerly;
//忽略無關代碼......
}
複製代碼
serviceMethodCache 是一個HashMap,它的Key是Method,表明咱們定義的網絡請求接口類中的方法,它的Value是ServiceMethod,表明對網絡請求接口類中的方法的一個封裝,簡單看一下它就明白了:bash
final class ServiceMethod<R, T> {
private final okhttp3.Call.Factory callFactory;
private final CallAdapter<R, T> callAdapter;
private final HttpUrl baseUrl;
private final Converter<ResponseBody, R> responseConverter;
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
//忽略無關代碼.......
}
複製代碼
很明顯了,ServiceMethod就是對網絡請求參數的封裝類,包含請求頭、相對url、GET請求或者是POST請求等等對請求的配置信息。serviceMethodCache 就是一個對ServiceMethod的緩存,能夠提升必定的效率。網絡
在Retrofit中,默認的數據轉換器工廠就是 GsonConverterFactory ,因此其實若是咱們是使用 Gson 來作數據轉換的,其實沒有必要去配置。在Android平臺,Retrofit中默認的網絡請求適配器工廠是 ExecutorCallAdapterFactory ,咱們簡單瞅一眼它是如何被建立的:框架
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
//注意這裏建立了一個位於主線程的Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
//經過handler.post(runnable)實現線程切換
handler.post(r);
}
}
}
複製代碼
能夠看到,在建立 ExecutorCallAdapterFactory 的同時傳入了一個 callbackExecutor ,這個 callbackExecutor 也是Retrofit中默認的 callbackExecutor ,在Android平臺中它是 MainThreadExecutor類型 ,能夠看到,在它的內部建立了一個位於主線程的Handler。咱們知道,使用Retrofit的時候不一樣於直接使用OKHttp,在使用Retrofit的異步網絡請求時,網絡結果的回調是位於主線程中的,那麼Retrofit是如何切換的線程,看過上面的代碼應該會內心有個數了,它是經過 handler.post(r) 來實現由子線程到主線程的切換。異步
看過個人Retrofit源碼分析第二篇:代理模式的小夥伴們應該都比較清楚了,在Retrofit的 create 方法中實際上是使用了動態代理生成了一個代理對象,如今咱們就來看一下 create 的源碼:ide
public <T> T create(final Class<T> service) {
//忽略無關代碼......
//下面就是JDK給咱們提供的動態代理了
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 {
//忽略無關代碼......
//獲取method的網絡請求參數的封裝類ServiceMethod對象
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//獲取對OKHttp中的RealCall的一個包裝類OkHttpCall對象
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//經過網絡請求適配器將原始的Call對象轉換成須要的對象,好比RxJavaCallAdapter會將Call對象轉換成Observable。
return serviceMethod.adapt(okHttpCall);
}
});
}
複製代碼
在 create 方法中作了3件事:
final class OkHttpCall<T> implements Call<T> {
//忽略無關代碼......
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
//熟悉OkHttp源碼的同窗應該很熟悉了,徹底照抄OkHttp中的代碼,確保每一個Call只會被執行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
//忽略無關代碼......
call = rawCall;
if (call == null) {
try {
//建立OkHttp中的RealCall對象
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//解析OkHttp中的RealCall執行同步方法後返回的網絡數據
return parseResponse(call.execute());
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
//確保一個Call對象只被執行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//建立OkHttp中的RealCall對象
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//調用OkHttp中的RealCall的異步請求網絡方法
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) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
}
複製代碼
能夠看到,Retrofit中的這個 OKHttpCall 徹底是對OkHttp中的 RealCall 的一個包裝。在 OKHttpCall 中的同步網絡方法 execute 和異步網絡方法 enQueue 中其實就作了三件事:獲取 RealCall 對象,調用 RealCall 中的 execute 或者 enQueue 方法,而後去解析OkHttp返回的原始數據並轉換成咱們須要的類型,就這麼簡單。
接下來就 create 方法中就只剩下 經過CallAdapter轉換Call對象 了,咱們上面說過,在沒有特別配置CallAdapter的時候,默認的CallAdapterFactory是 ExecutorCallAdapterFactory ,很明顯,CallAdapter是由Factory建立的,那咱們看一下這個默認的CallAdapterFactory:
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
//本質是傳入的MainThreadExecutor
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);
//直接建立並返回一個CallAdapter的匿名對象
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
//返回默認的CallAdapter轉換後的Call對象
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
//本質是傳入的MainThreadExecutor
final Executor callbackExecutor;
//就是OKHttpCall,從名字也能理解,代理Call對象
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");
//調用OkHttp中RealCall的異步網絡請求
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//注意,OkHttp的異步回調是在子線程的,Retrofit這裏實現了線程的切換,本質是調用了handler.post(runnable)
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
//注意,OkHttp的異步回調是在子線程的,Retrofit這裏實現了線程的切換,本質是調用了handler.post(runnable)
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
//因爲同步方法不須要切線程,因此直接執行並返回OKHttpCall的同步網絡方法
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}
複製代碼
上面的代碼其實也很清晰了 ExecutorCallAdapterFactory 這個CallAdapter工廠類直接建立並返回一個CallAdapter的匿名對象,這個其實就是咱們Retrofit的默認CallAdapter,關鍵是這個CallAdapter的adapt方法,它返回了 ExecutorCallbackCall 這個對OkHttpCall的包裝類,咱們關注這個包裝類的 enqueue 方法,在這個方法中,它經過調用 callbackExecutor.execute
來實現了子線程到主線程的線程切換。這個 callbackExecutor 就是 MainThreadExecutor ,這個類咱們上面提到過, MainThreadExecutor 中的 execute 方法內部就是 handler.post(r);
,這個 handler 其實就是主線程的,所以實現了線程切換。
其實通過上一步的分析,咱們已經知道了,咱們獲取的Call對象,實際上是經過動態代理中 serviceMethod.adapt(okHttpCall)
返回的Call對象,這個其實就是 ExecutorCallbackCall ,這個咱們都很清楚了,它是對OkHttp中RealCall的一個包裝類,在它的異步方法中經過調用 callbackExecutor.execute
實現了線程的切換,固然本質仍是經過 Handler 機制。
其實到此爲止,基本的流程已經分析完畢了,咱們到這裏也會很清楚Retrofit的定位:Retrofit並非一個網絡請求的框架,而是一封裝網絡請求參數,解析網絡返回結果的框架。下面咱們來分析一下使用了RxJava2CallAdapter的狀況。
CallAdapter的重點是它的adapt方法,咱們來看一下RxJava2CallAdapter中的adapt方法:
@Override public <R> Object adapt(Call<R> call) {
//建立一個發射網絡返回結果的Observable
Observable<Response<R>> responseObservable = new CallObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
//默認scheduler爲空
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,咱們看一下 CallObservable 的內部實現,看過RxJava2源碼的同窗應該都知道,Observable的關鍵方法是 subscribeActual,咱們就看一下這個方法內部都作了什麼:
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// 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 {
//調用了OKHttpCall的同步網絡訪問方法,並獲取網絡數據
Response<T> response = call.execute();
if (!call.isCanceled()) {
//將獲取到的網絡數據發送到觀察者observer
observer.onNext(response);
}
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);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
}
}
複製代碼
熟悉RxJava2的同窗看完就應該懂了:RxJava2CallAdapter經過adapt方法生成並返回一個 CallObservable 對象,在這個 CallObservable 內部通調用 OKHttpCall 的 execute() 方法進行網絡訪問,並將獲取到的數據發送到下一級的觀察者observer中。
到此爲止,Retrofit的源碼分析終於結束了,其實它並不難,但想要徹底理解整個網絡訪問流程,除了要明白Retrofit,還須要瞭解OKHttp甚至是RxJava,對後二者不太熟悉的小夥伴們能夠看個人另外兩篇源碼分析:OkHttp源碼分析 , RxJava2源碼分析 ,在熟悉了OKHttp和RxJava2的基礎上再回過頭來看Retrofit,相信你會有更深的理解。