以下都是本人收集和總結(jié)的內(nèi)容:
1. 什么是Retrofit
Retrofit是一個(gè) RESTful 的 HTTP 網(wǎng)絡(luò)請(qǐng)求框架的封裝。注意這里并沒有說它是網(wǎng)絡(luò)請(qǐng)求框架籽腕,主要原因在于網(wǎng)絡(luò)請(qǐng)求的工作并不是 Retrofit來完成的。Retrofit2.0 開始內(nèi)置 OkHttp
我們的應(yīng)用程序通過Retrofit請(qǐng)求網(wǎng)絡(luò),實(shí)際上是使用Retrofit接口層封裝請(qǐng)求參數(shù)敷待、Header、Url 等信息仁热,之后由OkHttp完成后續(xù)的請(qǐng)求操作榜揖,在服務(wù)端返回?cái)?shù)據(jù)之后,OkHttp將原始的結(jié)果交給Retrofit抗蠢,后者根據(jù)用戶的需求對(duì)結(jié)果進(jìn)行解析的過程举哟。講到這里,你就會(huì)發(fā)現(xiàn)所謂Retrofit迅矛,其實(shí)就是 Retrofitting OkHttp 了妨猩。
2. 如何實(shí)現(xiàn)Retrofit
2.1.定義請(qǐng)求接口
public interface GitHubService {
@GET("/users/{user}/repos")
List<Repo> listRepos(@Path("user") String user);
}
接口當(dāng)中的 listRepos 方法,就是我們想要訪問的 api 了, 如下:
https://api.github.com/users/{user}/repos
2.2.通過retrofit生成一個(gè)剛才定義接口的實(shí)現(xiàn)類
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
2.3.通過接口直接進(jìn)行請(qǐng)求
其中秽褒,在發(fā)起請(qǐng)求時(shí)壶硅, {user} 會(huì)被替換為方法的第一個(gè)參數(shù) octocat.
Call<List<Repo>> repos= service.listRepos("octocat");
發(fā)請(qǐng)求的代碼就像前面這一句,返回的 repos其實(shí)并不是真正的數(shù)據(jù)結(jié)果震嫉,它更像一條指令森瘪,你可以在合適的時(shí)機(jī)去執(zhí)行它:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
//執(zhí)行
Call<List<Repo>> repos = service.listRepos("octocat");
List<Repo> data = repos.execute();
2.4.參數(shù)的配置
發(fā)請(qǐng)求時(shí),需要傳入?yún)?shù)票堵,Retrofit 通過注解的形式令 Http 請(qǐng)求的參數(shù)變得更加直接扼睬,而且類型安全。
2.4.1 Query & QueryMap
@GET("/list")
Call<ResponseBody> list(@Query("page") int page);
Query 其實(shí)就是 Url 中 ‘?’ 后面的 key-value悴势,比如:
這里的tn=56060048_4_pg 就是一個(gè) Query窗宇,而我們?cè)谂渲盟臅r(shí)候只需要在接口方法中增加一個(gè)參數(shù)
這時(shí)候你肯定想,如果我有很多個(gè) Query特纤,多參數(shù)的版本的 QueryMap 橫空出世了军俊,使用方法如下
@GET("/list")
Call<ResponseBody> list(@QueryMap Map<String, String> options);
2.4.2 Field & FieldMap
其實(shí)我們用 POST 的場(chǎng)景相對(duì)較多,絕大多數(shù)的服務(wù)端接口都需要做加密捧存、鑒權(quán)和校驗(yàn)粪躬,GET顯然不能很好的滿足這個(gè)需求担败。使用 POST 提交表單的場(chǎng)景就更是剛需了,怎么提呢镰官?
@FormUrlEncoded
@POST("/")
Call<ResponseBody> example( @Field("name") String name,
@Field("occupation") String occupation);
其實(shí)也很簡(jiǎn)單提前,我們只需要定義上面的接口就可以了,我們用 Field聲明了表單的項(xiàng)泳唠,這樣提交表單就跟普通的函數(shù)調(diào)用一樣簡(jiǎn)單直接了狈网。
同樣多版本版本FieldMap,使用方式和QueryMap差不多笨腥,不講了
2.4.3 Part & PartMap
這個(gè)是用來上傳文件的
public interface FileUploadService {
@Multipart
@POST("upload")
Call<ResponseBody> upload(@Part("description") RequestBody description,
@Part MultipartBody.Part file);
}
如果你需要上傳文件拓哺,和我們前面的做法類似,定義一個(gè)接口方法脖母,需要注意的是士鸥,這個(gè)方法不再有 @FormUrlEncoded 這個(gè)注解,而換成了 @Multipart镶奉,后面只需要在參數(shù)中增加 Part
就可以了础淤。也許你會(huì)問,這里的 Part 和 Field 究竟有什么區(qū)別哨苛,其實(shí)從功能上講鸽凶,無非就是客戶端向服務(wù)端發(fā)起請(qǐng)求攜帶參數(shù)的方式不同,并且前者可以攜帶的參數(shù)類型更加豐富建峭,包括數(shù)據(jù)流玻侥。也正是因?yàn)檫@一點(diǎn),我們可以通過這種方式來上傳文件亿蒸,下面我們就給出這個(gè)接口的使用方法:
在實(shí)驗(yàn)時(shí)凑兰,我上傳了一個(gè)只包含一行文字的文件:
Visit me: http://www.println.net
那么我們?nèi)シ?wù)端看下我們的請(qǐng)求是什么樣的:
HEADERS
FORM/POST PARAMETERS
description: This is a description
RAW BODY
我們看到,我們上傳的文件的內(nèi)容出現(xiàn)在請(qǐng)求當(dāng)中了边锁。如果你需要上傳多個(gè)文件姑食,就聲明多個(gè) Part參數(shù),或者試試 PartMap
2.5 Converter茅坛,讓你的入?yún)⒑头祷仡愋拓S富起來
2.5.1 RequestBodyConverter
2.4.3 當(dāng)中音半,我為大家展示了如何用 Retrofit上傳文件,這個(gè)上傳的過程其實(shí)贡蓖。曹鸠。還是有那么點(diǎn)兒不夠簡(jiǎn)練,我們只是要提供一個(gè)文件用于上傳斥铺,可我們前后構(gòu)造了三個(gè)對(duì)象:
天哪彻桃,肯定是哪里出了問題。實(shí)際上晾蜘,Retrofit 允許我們自己定義入?yún)⒑头祷氐念愋土诰欤贿^眠屎,如果這些類型比較特別,我們還需要準(zhǔn)備相應(yīng)的 Converter肆饶,也正是因?yàn)?Converter 的存在组力,Retrofit 在入?yún)⒑头祷仡愋蜕媳憩F(xiàn)得非常靈活。
下面我們把剛才的 Service 代碼稍作修改:
public interface FileUploadService {
@Multipart
@POST("upload")
Call<ResponseBody> upload(@Part("description") RequestBody description,
//注意這里的參數(shù) "aFile" 之前是在創(chuàng)建 MultipartBody.Part 的時(shí)候傳入的
@Part("aFile") File file);
}
現(xiàn)在我們把入?yún)㈩愋透某闪宋覀兪煜さ?File抖拴,如果你就這么拿去發(fā)請(qǐng)求,服務(wù)端收到的結(jié)果會(huì)讓你哭了的腥椒。阿宅。。
RAW BODY
服務(wù)端收到了一個(gè)文件的路徑,這明顯是 Retrofit 在發(fā)現(xiàn)自己收到的實(shí)際入?yún)⑹莻€(gè) File時(shí)饭豹,不知道該怎么辦翎承,情急之下給 toString了脓豪,而且還是個(gè) JsonString(后來查證原來是使用了 GsonRequestBodyConverter。往湿。)。
接下來我們就自己實(shí)現(xiàn)一個(gè) FileRequestBodyConverter
static class FileRequestBodyConverterFactory extends Converter.Factory {
@Override
public Converter<File, RequestBody> requestBodyConverter(Type type, Annotation[]
parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new FileRequestBodyConverter();
}
}
static class FileRequestBodyConverter implements Converter<File, RequestBody> {
@Override
public RequestBody convert(File file) throws IOException {
return RequestBody.create(MediaType.parse("application/otcet-stream"), file);
}
}
在創(chuàng)建 Retrofit 的時(shí)候記得配置上它:
addConverterFactory(new FileRequestBodyConverterFactory())
這樣惋戏,我們的文件內(nèi)容就能上傳了领追。來,看下結(jié)果吧:
RAW BODY
文件內(nèi)容成功上傳了.
2.5.2 ResponseBodyConverter
前面我們?yōu)榇蠹液?jiǎn)單示例了如何自定義 RequestBodyConverter响逢,對(duì)應(yīng)的绒窑,Retrofit 也支持自定義 ResponseBodyConverter。
我們?cè)賮砜聪挛覀兌x的接口:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
返回值的類型為 List<Repo>舔亭,而我們直接拿到的原始返回肯定就是字符串(或者字節(jié)流)些膨,那么這個(gè)返回值類型是怎么來的呢?首先說明的一點(diǎn)是钦铺,GitHub 的這個(gè) api 返回的是 Json 字符串订雾,也就是說,我們需要使用 Json 反序列化得到 List<Repo>矛洞,這其中用到的其實(shí)是 GsonResponseBodyConverter洼哎。
問題來了,如果請(qǐng)求得到的 Json 字符串與返回值類型不對(duì)應(yīng)缚甩,比如:
接口返回的 Json 字符串:
{"err":0, "content":"This is a content.", "message":"OK"}
返回值類型
class Result {
int code;//等價(jià)于 err
String body;//等價(jià)于 content
String msg;//等價(jià)于 message
}
這種情況下谱净, Gson 就是再牛逼,也只能默默無語倆眼淚了擅威,它哪兒知道字段的映射關(guān)系怎么這么任性啊壕探。好,現(xiàn)在讓我們自定義一個(gè) Converter 來解決這個(gè)問題吧郊丛!
當(dāng)然李请,別忘了在構(gòu)造 Retrofit 的時(shí)候添加這個(gè) Converter瞧筛,這樣我們就能夠愉快的讓接口返回 Result 對(duì)象了。
注意5贾选较幌!Retrofit 在選擇合適的 Converter 時(shí),主要依賴于需要轉(zhuǎn)換的對(duì)象類型白翻,在添加 Converter 時(shí)乍炉,注意 Converter 支持的類型的包含關(guān)系以及其順序。
3.結(jié)合Retrofit源碼深度學(xué)習(xí)
retrofit的最大特點(diǎn)就是解耦滤馍,要解耦就需要大量的設(shè)計(jì)模式
精簡(jiǎn)流程圖
舉個(gè)列子岛琼,跟隨他進(jìn)入主題
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
//執(zhí)行
Call<List<Repo>> repos = service.listRepos("octocat");
List<Repo> data = repos.execute();
3.1首先通過@GET來標(biāo)識(shí)這個(gè)接口是一個(gè)GET請(qǐng)求。那么看一下這個(gè)GET注解的定義巢株。
@Documented
//@Target表示Annotation可用在什么地方槐瑞。
//METHOD:方法聲明
@Target(METHOD)
//@Retention表示在什么級(jí)別保存該注解信息
//RUNTIME:VM會(huì)在運(yùn)行時(shí)保留注解,這時(shí)可以通過反射讀取注解信息
@Retention(RUNTIME)
public @interface GET {
String value() default "";
}
3.2 接下來看一下是如何創(chuàng)建Retrofit對(duì)象的阁苞。
public final class Retrofit {
......代碼省略.......
//對(duì)平臺(tái)的支持
private Platform platform;
//發(fā)起請(qǐng)求OKHttp3的Client工廠
private okhttp3.Call.Factory callFactory;
//OKHttp2的HttpUrl對(duì)象困檩,也就是將我們傳入的baseUrl字符串包裝成HttpUrl
private HttpUrl baseUrl;
//轉(zhuǎn)換器工廠集合,retrofit可以插入多個(gè)轉(zhuǎn)化器那槽,例如:Gson悼沿,Jackson等等
private List<Converter.Factory> converterFactories = new ArrayList<>();
//用于發(fā)起請(qǐng)求和接收響應(yīng)的Call適配器工廠集合,
//Retrofit對(duì)RxJava的支持就是通過在該集合中添加RxJavaCallAdapterFactory,
//而RxJavaCallAdapterFactory正是繼承自CallAdapter.Factory
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
//Executor并發(fā)框架骚灸,用于對(duì)請(qǐng)求后響應(yīng)結(jié)果的回調(diào)執(zhí)行
private Executor callbackExecutor;
//是否需要立即生效
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
//對(duì)屬性的配置
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);
//默認(rèn)添加ExecutorCallAdapterFactory 显沈,先記住~~~~~~
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(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
......代碼省略.......
}
Builder中的Platform.get()做什么了?我們繼續(xù)點(diǎn)擊查看:
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
//通過findPlatform方法我們可以看出Retrofit支持三個(gè)平臺(tái)
private static Platform findPlatform() {
try {
//Android
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
//java
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
try {
//IOS,這里的IOS指的是RoboVM。
//RoboVM它是一種可以在iOS設(shè)備上運(yùn)行Java應(yīng)用程序的技術(shù)逢唤,這種技術(shù)主要還是用于在游戲開發(fā)中拉讯。
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
//默認(rèn)為null,子類重寫賦值
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
}
當(dāng)前平臺(tái)為Android平臺(tái)之后返回一個(gè)Android對(duì)象鳖藕,這個(gè)Android類是Platform中的一個(gè)靜態(tài)內(nèi)部類魔慷。我們看看他做了什么
static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
//重寫父類,返回的Handler對(duì)象
return new MainThreadExecutor();
}
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
//網(wǎng)絡(luò)請(qǐng)求時(shí)分析ExecutorCallAdapterFactory做了什么
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
3.3 接下來直入重點(diǎn),Retrofit對(duì)象的創(chuàng)建OK以后,便通過Reetrofit中的create方法創(chuàng)建一個(gè)我們請(qǐng)求接口,其實(shí)創(chuàng)建的一個(gè)代理對(duì)象了著恩,這里涉及點(diǎn)兒 Java 的動(dòng)態(tài)代理的知識(shí)院尔,直接來看create代碼:
public final class Retrofit {
......代碼省略.......
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//這里返回一個(gè)service的代理對(duì)象
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, 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);
}
//每一個(gè)接口最終初始化一個(gè)serviceMethod
ServiceMethod serviceMethod = loadServiceMethod(method);
//并且Retrofit 與 Okhttp 完全耦合
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//發(fā)送請(qǐng)求,并且解析服務(wù)端返回的結(jié)果
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
//這個(gè)方法通過反射獲取我們創(chuàng)建service接口中所有的接口方法喉誊,然后根據(jù)接口方法和當(dāng)前的
//retrofit對(duì)象來獲得ServiceMethod并且以接口方法作為Key邀摆,
//ServiceMethod作為值添加到serviceMethodCache緩存中
//下次便可以通過接口方法直接獲取ServiceMethod
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//初始化ServiceMethod,并且執(zhí)行serviceMethod.callAdapter
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
......代碼省略.......
}
總結(jié)下伍茄,當(dāng)我們通過代理類(也就是我們調(diào)用create方法后返回的service)調(diào)用我們所創(chuàng)建的接口方法時(shí)栋盹。InvocationHandler中的invoke方法將會(huì)被調(diào)用。在invoke方法中由于method.getDeclaringClass()獲取到的是一個(gè)接口敷矫,并不是Object類例获,所以第一個(gè)條件不成立汉额。而在Android平臺(tái)下platform.isDefaultMethod(method)返回的為false,所以這個(gè)條件也不成立榨汤。之后通過loadServiceMethod方法來獲取ServiceMethod蠕搜。最后調(diào)用ServiceMethod中callAdapter的adapt方法。而ServiceMethod中的callAdapter屬性是通過ServiceMethod中createCallAdapter方法所創(chuàng)建收壕。在createCallAdapter中實(shí)際上是調(diào)用了Retrofit中的callAdapter方法來對(duì)ServiceMethod中的callAdapter進(jìn)行初始化妓灌。
簡(jiǎn)單的說,在我們調(diào)用 GitHubService.listRepos 時(shí)蜜宪,實(shí)際上調(diào)用的是這里的InvocationHandler.invoke 方法~~
3.4 下面再看一下ServiceMethod中的callAdapter方法如何執(zhí)行旬渠,
final class ServiceMethod<T> {
final Retrofit retrofit;
final Method method;
final Annotation[] methodAnnotations;
final Annotation[][] parameterAnnotationsArray;
final Type[] parameterTypes;
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
callAdapter = createCallAdapter();
......省略代碼......
return new ServiceMethod<>(this);
}
private CallAdapter<?> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//注意這里調(diào)用Retrofit的callAdapter
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
}
接下來查看Retrofit的callAdapter做了什么
public final class Retrofit {
.......省略代碼.........
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
//通過遍歷adapterFactories并根據(jù)我們的接口方法所中返回值類型來獲取相應(yīng)的適配器callAdapter。
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
.......省略代碼.........
}
總結(jié):通過遍歷adapterFactories并根據(jù)我們的接口方法所中返回值類型來獲取相應(yīng)的適配器callAdapter,如果我們想返回的是RxJava中Observable對(duì)象端壳, 那我們添加了RxJavaCallAdapterFactory,那么返回的就是RxJavaCallAdapter枪蘑。如果沒有添加那么此處的adapter為null损谦,便會(huì)拋出異常。在正是通過這種適配器模式完成了對(duì)RxJava的完美結(jié)合岳颇。
Call<List<Repo>> repos = service.listRepos("octocat");
List<Repo> data = repos.execute();
service.listRepos("octocat")照捡;這個(gè)方法到底怎么執(zhí)行的我們上面還遺留了一個(gè)ExecutorCallAdapterFactory方法接下來我們一步一步研究它
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
//get方法返回一個(gè)CallAdapter對(duì)象,
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
//adapt方法返回ExecutorCallbackCall對(duì)象,它實(shí)現(xiàn)了Retrofit中的Call接口
//其實(shí)就是InvocationHandler.invoke 那個(gè)callAdapter的實(shí)現(xiàn)類
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(final Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(call, new IOException("Canceled"));
} else {
callback.onResponse(call, response);
}
}
});
}
@Override public void onFailure(final Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(call, t);
}
});
}
});
}
......
}
從ExecutorCallAdapterFactory類中可看出通過get方法返回一個(gè)CallAdapter對(duì)象话侧,從對(duì)CallAdapter的實(shí)現(xiàn)中可以看出在CallAdapter中的adapt方法返回的是ExecutorCallbackCall對(duì)象栗精。它實(shí)現(xiàn)了Retrofit中的Call接口。到這里我們也就明白了瞻鹏,當(dāng)通過代理調(diào)用我們創(chuàng)建的接口方法中所返回的Call對(duì)象就是這個(gè)ExecutorCallbackCall悲立。當(dāng)我們通過call.enqueue來完成網(wǎng)絡(luò)請(qǐng)求操作實(shí)際上就是調(diào)用ExecutorCallbackCall中的enqueue方法。在ExecutorCallbackCall中enqueue又將網(wǎng)絡(luò)請(qǐng)求委托給OkHttpCall去執(zhí)行新博。而這個(gè)OkHttpCall正是我們?cè)赗etrofit的create方法中所創(chuàng)建的OkHttpCall薪夕。由于OKHttp的CallBack接口中的onResponse和onFailure是在子線程中執(zhí)行的,所以在這時(shí)候又通過callbackExecutor將CallBack的onResponse和onFailure切換到主線程中執(zhí)行赫悄。
有了上面分析后我們知道repos.execute()其實(shí)就是一個(gè) OkHttpCall 實(shí)例原献,execute 就是要發(fā)起網(wǎng)絡(luò)請(qǐng)求
那么點(diǎn)進(jìn)去看看Call 的接口:
public interface Call<T> extends Cloneable {
//同步發(fā)起請(qǐng)求
Response<T> execute() throws IOException;
//異步發(fā)起請(qǐng)求,結(jié)果通過回調(diào)返回
void enqueue(Callback<T> callback);
boolean isExecuted();
void cancel();
boolean isCanceled();
Call<T> clone();
//返回原始請(qǐng)求
Request request();
}
然后在繼續(xù)查看OkHttpCall
final class OkHttpCall<T> implements Call<T> {
@Override public Response<T> execute() throws IOException {
//這個(gè)call 是 Okhttp的call埂淮,本質(zhì)對(duì)okhttpcall做了一層封裝
okhttp3.Call call;
synchronized (this) {
//處理重復(fù)執(zhí)行的邏輯
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//發(fā)送請(qǐng)求姑隅,并解析結(jié)果
return parseResponse(call.execute());
}
.......省略代碼.........
}
我們看到 OkHttpCall 其實(shí)也是封裝了 okhttp3.Call,在這個(gè)方法中倔撞,我們通過 okhttp3.Call 發(fā)起了進(jìn)攻讲仰,額,發(fā)起了請(qǐng)求痪蝇。有關(guān) OkHttp 的內(nèi)容叮盘,我在這里就不再展開了秩贰。
parseResponse 主要完成了由 okhttp3.Response 向 retrofit.Response 的轉(zhuǎn)換,同時(shí)也處理了對(duì)原始返回的解析:
final class OkHttpCall<T> implements Call<T> {
......省略代碼.........
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
//略掉一些代碼
try {
//在這里完成了原始 Response 的解析柔吼,T 就是我們想要的結(jié)果毒费,
//比如GitHubService.listRepos 的 List<Repo>
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
.......省略代碼.........
}
3.5 結(jié)果適配,你是不是想用 RxJava愈魏?
前面我們已經(jīng)提到過 CallAdapter的事兒觅玻,默認(rèn)情況下,它并不會(huì)對(duì) OkHttpCall 實(shí)例做任何處理:
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
... 毫不留情的省略一些代碼 ...
return new CallAdapter<Call<?>>() {
... 省略一些代碼 ...
@Override
public <R> Call<R> adapt(Call<R> call) {
//看這里培漏,直接把傳入的 call 返回了
return call;
}};
}
}
現(xiàn)在的需求是溪厘,我想要接入 RxJava,讓接口的返回結(jié)果改為 Observable:
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Observable<List<Contributor>> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
Retrofit 的開發(fā)者們?cè)缇拖氲搅诉@個(gè)問題牌柄,并且為我們提供了相應(yīng)的 Adapter畸悬,只需在構(gòu)造 Retrofit時(shí),添加它:
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
這樣我們的接口就可以以 RxJava 的方式工作了珊佣。
接著我們搞清楚 RxJavaCallAdapterFactory 是怎么工作的蹋宦,首先讓我們來看下 CallAdapter
的接口:
public interface CallAdapter<T> {
//返回http解析后的類型,需注意這個(gè)類型并不是接口返回的類型咒锻,而是
//接口返回類型中泛型參數(shù)的實(shí)參
Type responseType();
//T 是我們需要轉(zhuǎn)換成接口返回的類型冷冗。參數(shù)call 其實(shí)最初就是okhttpcall的實(shí)例
//在這里T 其實(shí)是rxjava 支持的類型 ,比如 observable
<R> T adapt(Call<R> call);
//我們需要將Factory的子類對(duì)應(yīng)的實(shí)例在構(gòu)造 retrofit 時(shí)添加到其中
abstract class Factory {
//根據(jù)接口的返回類型(observable<T>)惑艇。注釋類型等等來判斷是否當(dāng)前adapter 支持的類型蒿辙,不是則返回null
public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
//獲取指定index的泛型參數(shù)的上限,比如對(duì)于
//map <string, ? extends number >, index 為1 時(shí)的參數(shù)上限是number
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
//獲取原始類型滨巴,比如List<String> 返回list.class 這里傳入的type情況
//可能比較復(fù)雜思灌,不能直接當(dāng)做class 去做判斷,這個(gè)方法在判斷類型是否
//為支持的類型時(shí)經(jīng)常用到
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
代碼中做了較為詳細(xì)的注釋恭取,簡(jiǎn)單來說习瑰,我們只需要實(shí)現(xiàn) CallAdapter 類來提供具體的適配邏輯,并實(shí)現(xiàn)相應(yīng)的 Factory秽荤,用來將當(dāng)前的 CallAdapter注冊(cè)到 Retrofit 當(dāng)中甜奄,并在 Factory.get方法中根據(jù)類型來返回當(dāng)前的 CallAdapter 即可(如果對(duì)這個(gè)方面或者邏輯混亂的話,可以把3.3和3.4的流程在走一遍你就會(huì)明白 了)窃款。知道了這些课兄,我們?cè)賮砜?RxJavaCallAdapterFactory:
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
.......省略代碼.........
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//下面代碼主要判斷returntype 是否為rxjava 支持的類型
Class<?> rawType = getRawType(returnType);
String canonicalName = rawType.getCanonicalName();
boolean isSingle = "rx.Single".equals(canonicalName);
boolean isCompletable = "rx.Completable".equals(canonicalName);
if (rawType != Observable.class && !isSingle && !isCompletable) {
return null;
}
if (!isCompletable && !(returnType instanceof ParameterizedType)) {
String name = isSingle ? "Single" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + "<Foo> or " + name + "<? extends Foo>");
}
if (isCompletable) {
return CompletableHelper.createCallAdapter(scheduler);
}
CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);
if (isSingle) {
return SingleHelper.makeSingle(callAdapter);
}
return callAdapter;
}
static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {
private final Type responseType;
private final Scheduler scheduler;
SimpleCallAdapter(Type responseType, Scheduler scheduler) {
this.responseType = responseType;
this.scheduler = scheduler;
}
@Override public Type responseType() {
return responseType;
}
@Override public <R> Observable<R> adapt(Call<R> call) {
在這里創(chuàng)建需作為返回值的 observable 實(shí)例,并持有call 的實(shí)例
當(dāng)observable.subscribe 觸發(fā)時(shí)晨继,call.execute 將會(huì)調(diào)用
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
.lift(OperatorMapResponseToBodyOrError.<R>instance());
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
}
.......省略代碼.........
}
至此烟阐,Retrofit 大部分結(jié)構(gòu)源碼有了新的認(rèn)知。