Retrofit,OkHttp,Okio Square 安卓平臺網路層三板斧原始碼學習
基於 retrofit 2.4.0-SNAPSHOT 版本 retrofit github 地址 :
https://github.com/square/retrofit
複製程式碼
Retrofit 是 Square 安卓平臺網路層三板斧最後一個專案,Retrofit 依賴 OkHttp 。Retrofit 讓 http 網路請求更加清晰。
使用方式
一、宣告一個介面,並用介面描述 request
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
複製程式碼
二、方法上面的註釋表示 request 的介面名 ,方法的返回型別就是 http 請求的返回值,方法的引數就是 http 的請求引數。
建立一個 Retrofit 客戶端
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
複製程式碼
Retrofit 建立的時候指定了 request 的介面地址,然後呼叫 retrofit.create 方法建立一個 GitHubService 例項。
三、發起網路請求
Call<List<Repo>> repos = service.listRepos("octocat");
repos.execute().body()
複製程式碼
上面的例子可以看到,retrofit.create() 方法會建立一個 GitHubService 例項,但是 GitHubService 本身是一個介面。為了瞭解 retrofit.create() 方法,我們先看下 Retrofit 的建立過程。
Retrofit 建立 Service 例項
建立 Retrofit 物件。
Retrofit 和 OkHttp 一樣都是使用構建者模式建立物件。先看下 Retrofit.Builder 的 build() 方法。
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);
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);
}
複製程式碼
建立 Retrofit 的時候需要傳遞一下幾個引數
-
callFactory 用來建立一個實現了 okhttp3.Call.Factory 的物件,如果沒有設定,預設為 OkHttpClient。
-
baseUrl 網路介面的地址。 -converterFactories 用來把伺服器返回的資料轉換為物件。
-
adapterFactories 用來發起網路請求。
-
callbackExecutor 是一個排程器,用來接收返回的資料,在 Android 上預設是封裝了 handler 的 MainThreadExecutor
-
validateEagerly 是一個開關,如果為 true 會快取建立的 ServiceMethod 。
我們再來看一下retrofit.create()原始碼
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(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 {
// 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);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
複製程式碼
這裡用到了一個公共技術點之 Java 動態代理,create 方法傳入一個 Class ,這個 Class 物件就是上文的 GitHubService 的 Class 。
GitHubService 的方法是由 InvocationHandler 代理實現的,重點看三行程式碼
......
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
複製程式碼
第一行 loadServiceMethod(method)
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;
}
複製程式碼
這裡建立了一個 ServiceMethod 物件。
第二行 new OkHttpCall<>(serviceMethod, args)
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
複製程式碼
建立了一個 OkHttpCall ,serviceMethod 和 args 是 OkHttpCall 的成員函式。
所以,
第三行 serviceMethod.callAdapter.adapt(okHttpCall)
這裡需要明白 serviceMethod.callAdapter 是怎麼來的
1. 在 ServiceMethod.Builder.build() 中呼叫 createCallAdapter()
2. 在 createCallAdapter() 中會找到
(CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations)
3. 在 callAdapter() 中呼叫 nextCallAdapter
4. nextCallAdapter 會遍歷 adapterFactories 返回一個 CallAdapter。
複製程式碼
這裡再回頭看下 adapterFactories Retrofit.Builder.build() 方法中
List<CallAdapter.Factory> adapterFactories =
new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
複製程式碼
而在 Retrofit.nextCallAdapter() 中
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;
}
}
複製程式碼
如果沒有設定 AdapterFactory 將會使用一個預設的 AdapterFactory
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
複製程式碼
所以如果我們設定了一個 RxJavaCallAdapterFactory,就會返回 RxJavaCallAdapterFactory。
整個建立Retrofit的過程流程為:
發起網路請求
通過 retrofit.create() 我們可以知道,retrofit.create() 返回的是一個代理物件InvocationHandler ,那麼在執行
Call<List> repos = service.listRepos("octocat"); 方法時,呼叫的實際上是 callAdapter.adapt(okHttpCall),以 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;
}
};
}
複製程式碼
結合 retrofit.create() 方法可以得知這裡返回的是一個 OkHttpCall 物件。
接下來使用 OkHttpCall.execute() 或者非同步執行 enqueue(Callback callback)
這兩種方式都會呼叫 createRawCall() 建立一個 okhttp3.Call
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
複製程式碼
此處的 serviceMethod.callFactory 就是 retrofit.create() 中建立的 OkHttpClient() 後面的內容都是由 Okhttp 模組接管,進行網路請求,參考okHttp 框架原始碼學習
然後呼叫 parseResponse(call.execute())
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
……
省略一些 http 返回值處理邏輯
……
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} ……
}
複製程式碼
okHttp 請求網路的返回資料,會交給 serviceMethod.toResponse
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
複製程式碼
在 ServiceMethod.Builder.build() 方法中可以找到 responseConverter 是通過 createResponseConverter() 方法的返回物件。
createResponseConverter() 只是報包裹了 retrofit.responseBodyConverter(responseType, annotations) 方法。
retrofit.responseBodyConverter() 繼續跟蹤下去會得知,返回的是 converterFactories 陣列的第 0 個物件,也就是內建的 BuiltInConverters.responseBodyConverter() 方法返回的 BufferingResponseBodyConverter
static final class BufferingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
@Override
public ResponseBody convert(ResponseBody value) throws IOException {
try {
// Buffer the entire body to avoid future I/O.
return Utils.buffer(value);
} finally {
value.close();
}
}
}
複製程式碼
再看一下 Utils.buffer(value)
static ResponseBody buffer(final ResponseBody body) throws IOException {
Buffer buffer = new Buffer();
body.source().readAll(buffer);
return ResponseBody.create(body.contentType(), body.contentLength(), buffer);
}
複製程式碼
最終會返回一個重新封裝的 Okhttp 框架的 ResponseBody 物件,過程如下:
最後來個總結
-
第一步建立一個Retrofit物件
-
通過 Retrofit.onCreate()方法把我們所定義的介面轉化為介面例項並使用介面中的方法
-
最終的例項都會呼叫okHttp的call,retrofit用於OKhttp的,比較靈活
相信自己,沒有做不到的,只有想不到的
如果你覺得此文對您有所幫助,歡迎入群 QQ交流群 :232203809 微信公眾號:終端研發部