Retrofit是Square公司開發的一款針對Android網絡請求的框架,遵循Restful設計風格,咱們查看 invoke 能夠發現:底層基於OkHttp實現的 ,相比其餘網絡請求框架,有如下優點:java
固然也有弊端:由於高度封裝,相對於 OkHttp ,擴展性變差了,不過總體能知足項目需求.今天我就帶你們來看一下Retrofit到底是如何使用,以及內部工做原理node
OKHttp 作的更加簡潔,更加方便,同時影藏了oKHttp的某些功能。android
在運行的時候不會報類型錯誤,經過泛型策閱,將運行時異常提高到編譯期異常。git
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
複製代碼
<uses-permission android:name="android.permission.INTERNET"/>
複製代碼
訪問 小木箱 github 倉庫,經過get請求獲得瞭如下報文:github
class MicroKibacoRepo {
private int id;
private String node_id;
private String name;
private String full_name;
// ---爲了不浪費篇幅,省略無用代碼---
}
複製代碼
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<MicroKibacoRepo>> listRepos(@Path("user") String user);
}
複製代碼
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
複製代碼
Call<List<MicroKibacoRepo>> repos = service.listRepos("MicroKibaco");
複製代碼
repos.enqueue(new Callback<List<MicroKibacoRepo>>() {
@Override
public void onResponse(Call<List<MicroKibacoRepo>> call, Response<List<MicroKibacoRepo>> response) {
}
@Override
public void onFailure(Call<List<MicroKibacoRepo>> call, Throwable t) {
}
});
複製代碼
讀源碼如何開始呢?api
一行一行讀,確定是不可行的,太累了,並且腦容量不夠,記不住,合適的讀源碼方式是從程序入口開始入手。當前功能開始讀。網絡
當前請求的入口發生在enqueue, 那麼,咱們就開始從這個Api入手讀源碼.框架
enqueue, 是進入隊列的意思,進去查看,居然是個分佈式
void enqueue(Callback<T> callback);
複製代碼
若是出現相似抽象方法;就得往回看了,由於讀不下去了ide
因此咱們往上面找,上面的Api是 enqueue,去找 相關接口實現,找了半天,愛哭,接口實現是GithubService
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<MicroKibacoRepo>> listRepos(@Path("user") String user);
}
複製代碼
而GithubService.java是我本身建立的,怎麼辦呢? 繼續往回看,找呀找, 找到了Retrofit的初始化方法 create,整個源碼我就不翻出來了,翻一翻關鍵的部分,其中須要講述的APi有:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T)
// --------動態代理--------
Proxy.newProxyInstance(
// 提供動態類的實例
service.getClassLoader(),
// 獲取 GithubService 的實例,獲取須要動態代理類的接口,在 retrofit.create 傳入
new Class<?>[] { service },
//
new InvocationHandler() {
// 判斷接口平臺,是JDK 7.0/8.0 或者 Android/IOS
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
// 若是這個方法不是直接聲明的,那麼就直接調用了,兼容性,保護性,不至於越權
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// java 8 開始,接口運行有默認的方法實現了
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
static <T> void validateServiceInterface(Class<T> service) {
// 1. 驗證 GitHubService 是否爲一個接口
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
// 2.驗證 GitHubService 是否繼承其餘接口,只接受原生接口
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
// 3. 在被初始化的時候,是有一個初始化過程,會去讀註解,中間是有耗時的,分佈式加載網絡請求, validateEagerly 是方便調試的
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
複製代碼
Platform.java 看一下相關實現,裏面包含兩個平臺一個是 Java8 還有一個 Android,這個APi主要是平臺標識,知道就好了,沒什麼好說的
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
// Android 平臺
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
// Java8 平臺
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
複製代碼
loadServiceMethod 裏面也沒有 invoke,咱們經過 parseAnnotations 去找 一下invoke試試看可否找到,
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
複製代碼
ServiceMethod.java裏面,不過也是一個抽象方法 ,因而咱們往回看 parseAnnotations,看裏面是否有 invoke 的邏輯實現,找到了,好傢伙,parseAnnotations是ServiceMethod子類HttpServiceMethod實現方法,而HttpServiceMethod必定有invoke實現
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
// 經過 parseAnnotations 去尋找 invoke實現
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract T invoke(Object[] args);
}
複製代碼
不用說,我直接在HttpServiceMethod.java, ctr + f 搜,便搜到了invoke,原來底層真是經過OKHttp實現的:
final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
// ----爲了不浪費篇幅,省略若干無用代碼----
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
}
複製代碼
上面我說過,看到抽象方法,往回看 ,因此咱們來看 okHttpCall,OKHttpCall實現了Call接口 ,重點說一下一下方法:
// OKhttp3的Call幫助Retrofit實現網絡請求的Call
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
複製代碼
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
// response 結果交給 Retrofit 使用
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(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();
}
}
});
}
複製代碼
什麼是動態代理?
動態代理是建立一個對象,這個對象傳入一個接口而且幫你實現每個接口的每個方法,而且這每個接口的每個方法都會指向每個接口每個方法的invoke方法。
HttpServiceMethod.java裏面的構造方法, 咱們找到了 CallAdapter,而後去裏面查看是經過 createCallAdapter返回的
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method) {
Type returnType = method.getGenericReturnType();
Annotation[] annotations = method.getAnnotations();
try {
// CallAdapter 建立
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
複製代碼
進入 Retrofit.java 查看一下:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
// 經過 callAdapterFactories 獲取 callAdapter
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
// ----爲了不浪費篇幅,省略若干無用代碼----
}
複製代碼
callAdaperFactory是經過 Retrofit 的 build 方法構建而來.
public Retrofit build() {
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
複製代碼
咱們看到 callAdaperFactory 經過 addAll 一次性添加過來,因此有咱們看一下defaultCallAdapterFactories方法.
@Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
return Build.VERSION.SDK_INT >= 24
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
複製代碼
而後咱們再看一下 ExecutorCallAdapterFactory