使用Retrofit作爲Android網絡請求已經非常普遍了,並且Retrofit的源碼不僅少而且還很精妙,作爲閱讀學習的對象在合適不過了。雖然很久之前就用了,但是還真沒看過源碼,趁着最近空閒就試着看看把。本文Retrofit版本是 2.6.0。看完我覺得還是2.4之前會更輕鬆點吧,可惜我沒找到老版本的jar包
基本用法
要了解一個框架的源碼,肯定要知道它的基本用法。然後從基本用法裏選擇一個入口方法,這樣就可以跟着用法讀下去了。
1、定義請求接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<UserBean>> listRepos(@Path("user") String user);
}
2、初始化Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.client(new OkHttpClient())
//.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
3、網絡請求
Call<List<UserBean>> repos = service.listRepos("octocat");
{
repos.enqueue(new Callback<List<UserBean>>() {
@Override
public void onResponse(Call<List<UserBean>> call, Response<List<UserBean>> response) {
List<UserBean> list = response.body();
}
@Override
public void onFailure(Call<List<UserBean>> call, Throwable throwable) {
}
});
}
源碼閱讀
從上面3個使用步驟我們可以很明顯的看出retrofit.create()
是一個入口方法,首先先來看看Retrofit()中都初始化了啥。
一、Retrofit初始化
Retrofit通過Builder設計模式進行初始化。看一下build()
方法中都做了些什麼。
public Retrofit build() {
//初始化時baseUrl是必須的
if(this.baseUrl == null) {
throw new IllegalStateException("Base URL required.");
} else {
Object callFactory = this.callFactory;
//初始化時如果沒有設置client,callFactory 爲null
//默認創建一個OkHttpClient賦值給callFactory
if(callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if(callbackExecutor == null) {
callbackExecutor = this.platform.defaultCallbackExecutor();
}
//調用addCallAdapterFactory時初始化
//如果沒有初始化,使用DefaultCallAdapterFactory
ArrayList callAdapterFactories = new ArrayList(this.callAdapterFactories);
callAdapterFactories.addAll(this.platform.defaultCallAdapterFactories(callbackExecutor));
//調用addConverterFactory時候初始化,
//如果沒有初始化使用默認的BuiltInConverters
ArrayList converterFactories = new ArrayList(1 + this.converterFactories.size() + this.platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(this.platform.defaultConverterFactories());
return new Retrofit((Factory)callFactory, this.baseUrl, Collections.unmodifiableList(converterFactories), Collections.unmodifiableList(callAdapterFactories), callbackExecutor, this.validateEagerly);
}
}
構造Retrofit對象的時候初始化了三個非常重要的參數:
- callFactory
- CallAdapter
- ConverterFactory
1、callFactory ,即OkHttpClient,繼承Call.Factory。OKhttp的工廠類
2、CallAdapter。適配器模式,負責將Call對象轉換成我們需要的類型。例如Rxjava中的Observable對象。
如下默認login返回Call對象,當時用初始化時調用addCallAdapterFactory(RxJava2CallAdapterFactory.create())
給Retrofit添加一個RxJava的適配器的時候,則返回Observable對象
// 使用默認適配器時
Call<String> login();
// 添加Rxjava適配器時的返回
Observable<String> login();
3、ConverterFactory,轉換工廠。將http返回的response轉換成我們需要的對象。如UserBean。
二、構建service對象
GitHubService service = retrofit.create(GitHubService.class);
create方法源碼如下:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if(this.validateEagerly) {
this.eagerlyValidateMethods(service);
}
return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Nullable
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
return method.getDeclaringClass() == Object.class?method.invoke(this, args):(this.platform.isDefaultMethod(method)?
this.platform.invokeDefaultMethod(method, service, proxy, args):
Retrofit.this.loadServiceMethod(method).invoke(args != null?args:this.emptyArgs));
}
});
}
Create方法中完成了兩件事情:
1、使用代理模式動態創建一個Service對象並返回
2、創建ServiceMethod對象,並且調用invoke()方法。
關於動態代理和反射可以我的另外兩篇文章:
代理模式
Java反射機制
創建ServiceMethod對象
通過loadServiceMethod()方法獲得一個ServiceMethod。
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod result = (ServiceMethod)this.serviceMethodCache.get(method);
if(result != null) {
return result;
} else {
Map var3 = this.serviceMethodCache;
synchronized(this.serviceMethodCache) {
result = (ServiceMethod)this.serviceMethodCache.get(method);
if(result == null) {
result = ServiceMethod.parseAnnotations(this, method);
this.serviceMethodCache.put(method, result);
}
return result;
}
}
}
可以看到loadServiceMethod()方法中有個會對ServiceMethod對象進行緩存,當ServiceMethod對象爲null時,會調用ServiceMethod.parseAnnotations(this, method)
獲得一個ServiceMethod對象。
abstract class ServiceMethod<T> {
ServiceMethod() {
}
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if(Utils.hasUnresolvableType(returnType)) {
throw Utils.methodError(method, "Method return type must not include a type variable or wildcard: %s", new Object[]{returnType});
} else if(returnType == Void.TYPE) {
throw Utils.methodError(method, "Service methods cannot return void.", new Object[0]);
} else {
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
}
@Nullable
abstract T invoke(Object[] var1);
}
從上面源碼可以看出ServiceMethod是一個抽象類。通過parseAnnotations()方法獲得一個ServiceMethod對象。
獲得RequestFactory
看一下ServiceMethod.parseAnnotations方法,首先會調用RequestFactory.parseAnnotations方法,獲得一個RequestFactory 對象
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
那麼RequestFactory 又是什麼呢?
查看RequestFactory.parseAnnotations源碼如下
可以看到RequestFactory又是一個Builder模式。看一下Builder中的參數和方法
從上面的參數不難看出,這其實就是我們基本用法第一步中新建GitHubService 中的請求方法的解析。
@GET("users/{user}/repos")
Call<List<UserBean>> listRepos(@Path("user") String user);
比如解析上面的請求方法GET,路徑"users/{user}/repos",參數等等。
下面來看一下有哪些解析方法:
//解析Http請求的方法,get、post等
private void parseMethodAnnotation(Annotation annotation);
//解析Http請求的方法和路徑
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody);
//解析請求頭
private Headers parseHeaders(String[] headers)
//解析請求參數
private ParameterHandler<?> parseParameter(int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation)
//解析參數中的註解 例如@path。方法內調用ParameterHandler解析
private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation)
static Set<String> parsePathParameters(String path);
解析方法時有個非常重要的類ParameterHandler,具體的解析是由ParameterHandler來完成的。
現在我們已經知道了RequestFactory的作用了,解析http請求的方法,路徑,請求頭等和http請求相關的參數了。
繼續回到我們的ServiceMethod類中。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if(Utils.hasUnresolvableType(returnType)) {
throw Utils.methodError(method, "Method return type must not include a type variable or wildcard: %s", new Object[]{returnType});
} else if(returnType == Void.TYPE) {
throw Utils.methodError(method, "Service methods cannot return void.", new Object[0]);
} else {
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
}
通過反射獲得方法的返回類型:
Type returnType = method.getGenericReturnType();
然後調用HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
獲得一個HttpServiceMethod對象。
HttpServiceMethod
HttpServiceMethod繼承自ServiceMethod。
HttpServiceMethod構造方法如下:
HttpServiceMethod(RequestFactory requestFactory, Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) {
this.requestFactory = requestFactory;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
}
需要初始化三個非常重要的參數:
- requestFactory :service中的請求參數
- callFactory :Call的適配器
- responseConverter :response轉換器
HttpServiceMethod.parseAnnotations()源碼如下(有省略):
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
Annotation[] annotations = method.getAnnotations();
Object adapterType;
Type responseType;
...
adapterType = method.getGenericReturnType();
//創建一個Call適配器
CallAdapter callAdapter1 = createCallAdapter(retrofit, method, (Type)adapterType, annotations);
//獲得返回類型
responseType = callAdapter1.responseType();
...
//創建一個Converter
Converter responseConverter = createResponseConverter(retrofit, method, responseType);
Factory callFactory = retrofit.callFactory;
return (HttpServiceMethod)(new HttpServiceMethod.CallAdapted(requestFactory, callFactory, responseConverter, callAdapter1);
}
1、創建CallAdapter 對象
跟蹤createCallAdapter()方法,最終會調用Retrofit類中的nextCallAdapter()方法。源碼如下
public CallAdapter<?, ?> nextCallAdapter(@Nullable retrofit2.CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
Utils.checkNotNull(returnType, "returnType == null");
Utils.checkNotNull(annotations, "annotations == null");
int start = this.callAdapterFactories.indexOf(skipPast) + 1;
int builder = start;
int i;
for(i = this.callAdapterFactories.size(); builder < i; ++builder) {
CallAdapter count = ((retrofit2.CallAdapter.Factory)this.callAdapterFactories.get(builder)).get(returnType, annotations, this);
//獲得一個不爲null的CallAdapter 並且返回
if(count != null) {
return count;
}
}
...
throw new IllegalArgumentException(var8.toString());
}
nextCallAdapter()方法中遍歷callAdapterFactories集合中的CallAdapter,而callAdapterFactories則在Retrofit初始化的時候通過addCallAdapterFactory()賦值或者默認值。
當獲得一個不爲null的CallAdapter 的時候則返回。
2、創建Converter對象
通過responseType = callAdapter1.responseType();
得到response類型。
通過Converter responseConverter = createResponseConverter(retrofit, method, responseType);
創建一個responseConverter
跟蹤createResponseConverter()方法,最終在Retrofit中調用nextResponseBodyConverter()
方法,源碼如下:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(@Nullable retrofit2.Converter.Factory skipPast, Type type, Annotation[] annotations) {
Utils.checkNotNull(type, "type == null");
Utils.checkNotNull(annotations, "annotations == null");
int start = this.converterFactories.indexOf(skipPast) + 1;
int builder = start;
int i;
for(i = this.converterFactories.size(); builder < i; ++builder) {
Converter count = ((retrofit2.Converter.Factory)this.converterFactories.get(builder)).responseBodyConverter(type, annotations, this);
if(count != null) {
return count;
}
}
throw new IllegalArgumentException(var8.toString());
}
同樣獲得Retrofit初始化時Converter 對象並返回。通過addConverterFactory()方法初始化或者使用默認的Converter 。
3、獲得callFactory
通過Factory callFactory = retrofit.callFactory;
獲得一個Factory 對象。
同樣是在retrofit初始化的時候創建賦值。
4、返回HttpServiceMethod對象
new一個繼承自HttpServiceMethod 的 CallAdapted對象
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return this.callAdapter.adapt(call);
}
}
以上就是HttpServiceMethod類中的主要作用,到此ServiceMethod創建,我們需要再次回到Create()方法中。
創建OkHttpCall 對象
Create方法中完成了兩件事情:
1、使用代理模式動態創建一個Service對象並返回
2、創建ServiceMethod對象,並且調用invoke()方法。
上面ServiceMethod對象創建完畢,我們已經獲得一個ServiceMethod的實例對象HttpServiceMethod,現在執行HttpServiceMethod對象中的invoke()方法。
源碼如下:
final ReturnT invoke(Object[] args) {
OkHttpCall call = new OkHttpCall(this.requestFactory, args, this.callFactory, this.responseConverter);
return this.adapt(call, args);
}
在invoke方法中會創建並初始化一個OkHttpCall 對象,繼承Call對象。
三、請求網絡
Call<List<UserBean>> call = service.listRepos("octocat");
{
call.enqueue(new Callback<List<UserBean>>() {
@Override
public void onResponse(Call<List<UserBean>> call, Response<List<UserBean>> response) {
}
@Override
public void onFailure(Call<List<UserBean>> call, Throwable throwable) {
}
});
}
1、call.queue()源碼
調用ApiService中的請求方法,獲得一個Call返回值,通過call.enqueue()
執行網絡請求。
Call對象是一個接口,它的實現類是OkHttpCall ,所以真正網絡請求邏輯都在OkHttpCall 中
queue()方法源碼如下:
public void enqueue(final Callback<T> callback) {
okhttp3.Call call;//聲明一個okhttp請求call
Throwable failure;
...//省略一些空判斷,空處理
//執行okhttp請求,Retrofit是基於okhttp3進行封裝的網絡請求框架,
//真正請求網絡的部分還是OKhttp
call.enqueue(new okhttp3.Callback() {
//okhttp成功回調
public void onResponse(okhttp3.Call call, Response rawResponse) {
retrofit2.Response response;
try {
//解析成功的數據,返回我們需要的類型
response = OkHttpCall.this.parseResponse(rawResponse);
} catch (Throwable var6) {
Utils.throwIfFatal(var6);
this.callFailure(var6);
return;
}
try {
//外部callback回調
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable var5) {
Utils.throwIfFatal(var5);
var5.printStackTrace();
}
}
//OKhttp失敗回調
public void onFailure(okhttp3.Call call, IOException e) {
this.callFailure(e);
}
private void callFailure(Throwable e) {
try {
//外部Callback回調
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable var3) {
Utils.throwIfFatal(var3);
var3.printStackTrace();
}
}
});
}
從源碼可以看到,真正執行網絡請求的是OKhttp,而當請求成功的時候,okhttp成功回調中有一行很重要的代碼:
retrofit2.Response response;
//解析OKhttp返回的rawResponse,轉換成我們需要的response
response = OkHttpCall.this.parseResponse(rawResponse);
解析OKhttp成功返回結果
parseResponse()源碼如下:
retrofit2.Response<T> parseResponse(Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder().body(new OkHttpCall.NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();
int code = rawResponse.code();
if(code >= 200 && code < 300) {
if(code != 204 && code != 205) {
OkHttpCall.ExceptionCatchingResponseBody catchingBody1 = new OkHttpCall.ExceptionCatchingResponseBody(rawBody);
try {
//將Body數據轉換成我們需要的類型
Object e1 = this.responseConverter.convert(catchingBody1);
return retrofit2.Response.success(e1, rawResponse);
} catch (RuntimeException var9) {
catchingBody1.throwIfCaught();
throw var9;
}
} else {
rawBody.close();
return retrofit2.Response.success((Object)null, rawResponse);
}
} else {
...//省略
return e;
}
}
這裏面也有段非常核心的代碼:
Object e1 = this.responseConverter.convert(catchingBody1);
通過 responseConverter 調用 convert 方法實現類型轉換。
那麼responseConverter 是啥?
responseConverter 是一個Converter對象,負責將ResponseBody 轉換成 T 類型。
responseConverter 在哪賦值?
可以看到responseConverter 是在OKhttpCall的構造方法中進行初始化的
OKhttpCall的創建是在調用HttpServiceMethod 的 invoke() 方法中進行創建的,而responseConverter就是在HttpServiceMethod 中通過Converter responseConverter = createResponseConverter(retrofit, method, responseType);
進行創建的。
到此從Retrofit初始化到網絡結束已經完成。
因爲在Retrofit初始化的時候,初始化了一個 defaultCallbackExecutor。
Executor callbackExecutor = this.callbackExecutor;
if(callbackExecutor == null) {
callbackExecutor = this.platform.defaultCallbackExecutor();
}
而defaultCallbackExecutor 在Android平臺源碼如下
public Executor defaultCallbackExecutor() {
return new Platform.Android.MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
MainThreadExecutor() {
}
public void execute(Runnable r) {
this.handler.post(r);
}
}
可以看到這是一個在主線程的回調,所以我們可以直接在Retrofit的callback中進行進行ui操作。
Retrofit流程圖:
總結
Retrofit源碼閱讀到這裏了,其實還有不少爲什麼這樣做的問題還沒有消化,現在只是知道是這樣做這樣寫的。看之前也是做了些準備的,比如去學習了代理模式,反射,適配器模式,裝飾模式等。還好也沒準備一口氣喫個胖子,慢慢積累,過段時間再來看看會不會好點。