retrofit 已經流行好久了,它是Square開源的一款優秀的網絡框架,這個框架對okhttp進行了封裝,讓咱們使用okhttp作網路請求更加簡單。可是光學會使用只是讓咱們多了一個技能,學習其源碼才能讓咱們更好的成長。java
本篇文章是在分析retrofit的源碼流程,有大量的代碼,讀者最好把源碼下載下來導入IDE,而後跟着一塊兒看,效果會更好(文末有源碼獲取方式)android
interface GithubApiService {
@GET("users/{name}/repos")
Call<ResponseBody> searchRepoInfo(@Path("name") String name);
}
複製代碼
使用了註解代表請求方式,和參數類型,這是retrofit的特性,也正是簡化了咱們的網絡請求過程的地方!git
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
複製代碼
retrofit的實例化很簡單,採用鏈式調用的設計,把須要的參數傳進去便可,複雜的參數咱們這裏就不舉例了。github
GithubApiService githubService = retrofit.create(service)
Call<ResponseBody> call = githubService.searchRepoInfo("changmu175");
複製代碼
咱們調用retrofit的create方法就能夠把咱們定義的接口轉化成實現類,咱們能夠直接調用咱們定義的方法進行網絡請求,可是咱們只定義了一個接口方法,也沒有方法體,請求方式和參數類型都是註解,create是如何幫咱們整理參數,實現方法體的呢?一會咱們經過源碼解析再去了解。設計模式
//同步請求方式
call.request();
//異步請求方式
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//請求成功回調
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//請求與失敗回調
}
});
複製代碼
至此,retrofit的一次網絡請求示例已經結束,基於對okhttp的封裝,讓網絡請求已經簡化了不少。固然retrofit最適合的仍是REST API類型的接口,方便簡潔。api
下面咱們就看看retrofit的核心工做是如何完成的!安全
retrofit的初始化採用了鏈式調用的設計bash
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
複製代碼
很明顯這個方法是在傳一些須要的參數,咱們簡單的跟蹤一下:網絡
首先看看Builder()的源碼:框架
public Builder() {
this(Platform.get());
}
複製代碼
這句代碼很簡單就是調用了本身的另外一個構造函數:
Builder(Platform platform) {
this.platform = platform;
}
複製代碼
這個構造函數也很簡單,就是一個賦值,咱們把以前的Platform.get()點開,看看裏面作在什麼:
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
複製代碼
咱們發現這裏使用使用了一個餓漢式單例,使用Platform.get()返回一個實例,這樣寫的好處是簡單,線程安全,效率高,不會生成多個實例!
咱們再看看findPlatform() 裏作了什麼:
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
....省略部分代碼...
}
複製代碼
因此是判斷了一下系統,而後根據系統實例化一個對象。這裏面應該作了一些和Android平臺相關的事情,屬於細節,咱們追究,感興趣的能夠只看看。
再看看baseUrl(url)的源碼
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
....
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
....
this.baseUrl = baseUrl;
return this;
}
複製代碼
這兩段代碼也很簡單,校驗URL,生成httpUrl對象,而後賦值給baseUrl
看看build() 方法在作什麼
參數基本設置完了,最後就要看看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();
}
....
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}
}
複製代碼
代碼中有大量的參數校驗,有些複雜的參數咱們沒有傳,因此我就把那些代碼刪除了。簡單看一下也能知道,這段代碼就是作一些參數校驗,baseUrl不能爲空不然會拋異常,至於其餘的參數若是爲null則會建立默認的對象。其中callFactory就是okhttp的工廠實例,用於網絡請求的。
最後咱們看到,這個方法最終返回的是一個Retrofit的對象,初始化完成。
剛纔咱們就講過retrofit.create這個方法很重要,它幫咱們生成了接口實現類,並完成了方法體的建立,省去了咱們不少工做量。那咱們來看看它是如何幫咱們實現接口的。
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 {
// 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.adapt(okHttpCall);
}
});
}
複製代碼
這段代碼其實是使用了動態代理的設計模式,並且這個方法封裝的很是好,咱們只須要調用 方法就能夠得到咱們須要的實現類,遵循了迪米特法則(最少知道原則)。
瞭解動態代理的人都知道咱們要重寫Object invoke(Object proxy, Method method,[@Nullable](https://xiaozhuanlan.com/u/undefined) Object[] args)
方法,這個方法會傳入咱們須要的實現的方法,和參數,並返回咱們須要的返回值。
retrofit在重寫這個方法的時候作了三件事:
- 先判斷了這個方法的類是否是一個Object.class),就直接返回方法原有的返回值。
- 判斷這個方法是否是DefaultMethod,你們都知道這個方法是Java 8出來的新屬性,表示接口的方法體。
- 構建一個ServiceMethod<Object, Object>對象和OkHttpCall<Object>對象,並調用
serviceMethod.adapt(okHttpCall)方法將兩者綁定。
咱們看看這個方法的源碼:
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
複製代碼
這個callAdapter咱們在初始化retrofit的時候沒有使用:
addCallAdapterFactory(CallAdapterFactory)傳值,因此這裏是默認的DefaultCallAdapterFactory
那咱們再看看DefaultCallAdapterFactory裏的adapt(call)方法:
@Override public Call<Object> adapt(Call<Object> call) {
return call;
}
複製代碼
直接返回參數,也就是OkHttpCall<Object>的對象。因此若是沒有自定義callAdapter的時候,咱們定義接口的時候返回值類型應該是個Call類型的。
那麼,至此這個create方法已經幫咱們實現了咱們定義的接口,並返回咱們須要的值。
因爲文字過長的原因,咱們暫且分爲上下兩文,下文講講到請求參數整理丶Retrofit網絡請求已經本身的一些總結,固然凡事無絕對,只是本身Retrofit原理的一些見解
文章開頭說的源碼領取方式:關注我私信【資料】