一孕豹、簡單使用
具體使用流程和方法說明詳見:使用教程
簡單的代碼示例:
//步驟1:創(chuàng)建接口類
public interface WanAndroidService {
@GET("article/list/{index}/json")
Call<JsonObject> getArticles(@Path("index") int index);
}
//步驟2:構(gòu)建Retrofit實例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://wanandroid.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
//步驟3:通過Retrofit.create方法創(chuàng)建接口類的代理對象
WanAndroidService wanAndroidService = retrofit.create(WanAndroidService.class);
//步驟4:調(diào)用接口代理對象方法返回Call類實例或者其他自定義請求類
Call<JsonObject> articles = wanAndroidService.getArticles(0);
//步驟5:調(diào)用Call類實例的同步或者異步請求方法庆猫,發(fā)起網(wǎng)絡(luò)請求(.body()方法為獲取請求成功后返回的實體數(shù)據(jù)對象)
JsonObject body = articles.execute().body();
二登夫、原理分析
2.1拷邢、創(chuàng)建接口對象
2.1.1纸淮、源碼
步驟1和2比較簡單平斩,創(chuàng)建接口類,然后根據(jù)實際的情況構(gòu)建Retrofit類實例即可
源碼分析從步驟3Retrofit.create
方法開始:
public <T> T create(final Class<T> service) {
//校驗是否接口是否存在類型變量咽块,存在則拋出異常
//如果Retrofit實例設(shè)置了立即校驗绘面,會先解析注解,將結(jié)果保存到緩存中備用(詳解loadServiceMethod方法分析)
validateServiceInterface(service);
return (T)
//使用動態(tài)代理方法創(chuàng)建代理對象
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
//平臺信息類對象
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 如果方法來自O(shè)bject類,則調(diào)用Object類方法的默認(rèn)實現(xiàn)揭璃,不做任何處理.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
//isDefaultMethod(method)晚凿,判斷是否是java8并且是默認(rèn)實現(xiàn)方法
//如果是,則直接調(diào)用方法實現(xiàn)瘦馍,不做任何處理
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
//請求方法真正的調(diào)用邏輯
: loadServiceMethod(method).invoke(args);
}
});
}
2.1.2歼秽、總結(jié)
通過JDK動態(tài)代理技術(shù)生成我們定義請求接口的代理對象。
接口方法的調(diào)用最終會調(diào)用到
InvocationHandler
的invoke
方法情组。invoke方法內(nèi)部接口是否合法(非泛型接口)燥筷,并且不是Object的方法,接口方法也不存在默認(rèn)實現(xiàn)(JAVA8開始支持)呻惕,則最終調(diào)用
loadServiceMethod(method).invoke(args);
方法開始解析封裝網(wǎng)絡(luò)請求荆责。
2.2、接口方法調(diào)用
按照2.1的結(jié)論亚脆,接口方法的調(diào)用最終會調(diào)用到loadServiceMethod(method).invoke(args);
方法做院,具體源碼分析如下:
2.2.1、源碼
loadServiceMethod(method)
a. 解析注解濒持,生成ServiceMethod對象(loadServiceMethod(method)
)
ServiceMethod<?> loadServiceMethod(Method method) {
//先從緩存獲取键耕,緩存獲取到直接返回
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
//double check 再檢查一次緩存
result = serviceMethodCache.get(method);
if (result == null) {
//開始解析方法注解,生成ServiceMethod對象
result = ServiceMethod.parseAnnotations(this, method);
//緩存該方法對應(yīng)的ServiceMethod解析結(jié)果柑营,下次請求可以直接從緩存獲取
serviceMethodCache.put(method, result);
}
}
return result;
}
b. 解析注解屈雄,返回ServiceMethod對象(ServiceMethod.parseAnnotations(this, method)
)
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//生成RequestFactory對象,創(chuàng)建實例的同時會解析注解獲取網(wǎng)絡(luò)請求數(shù)據(jù)官套,解析的同時會校驗各個注解的合法性(比如請求方法注解必須是默認(rèn)GET/POST/...等等校驗)
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//獲取返回參數(shù)類型
Type returnType = method.getGenericReturnType();
//校驗返回參數(shù)類型酒奶,類型不能為以下類型:
//1、類型變量類型(T,E等等)奶赔、通配符表達(dá)式惋嚎、
//2、參數(shù)類型<>中的參數(shù)類型不能存在類型變量或者通配符(即可以是List<String>站刑、不能是List<T>或者List<?>另伍、
//3、泛型數(shù)組類型元素類型也不能存在類型變量或者通配符類型)
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
//返回類型也不能是void.class
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
//校驗通過調(diào)用HttpServiceMethod的parseAnnotations方法解析注解
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
c. 繼續(xù)解析注解绞旅,返回HttpServiceMethod對象(HttpServiceMethod.parseAnnotations(this, method, requestFactory)
)
//關(guān)鍵代碼
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
......
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
......
} else {
//獲取方法的返回參數(shù)類型
adapterType = method.getGenericReturnType();
}
//創(chuàng)建請求適配器(內(nèi)部通過CallAdpater.Factory創(chuàng)建摆尝,如果不自定義,并且方法返回值是Call因悲;則使用DefaultCallAdapterFactory創(chuàng)建CallAdapter堕汞;可以通過Retrofit配置新增Factory改變默認(rèn)行為)
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
......
//創(chuàng)建響應(yīng)數(shù)據(jù)轉(zhuǎn)換器(流程類似請求適配器創(chuàng)建)
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
//返回CallAdapted實例,傳遞的參數(shù)說明:
//1囤捻、requestFactory:內(nèi)部保存注解解析到的請求方法臼朗,請求參數(shù)邻寿,URL等等數(shù)據(jù);
//2视哑、callFactory:即OkHttpClient绣否;
//3、responseConverter:數(shù)據(jù)解析轉(zhuǎn)換器挡毅;
//4蒜撮、callAdapter:請求適配器,可以自定義實現(xiàn)線程切換等邏輯跪呈,Android默認(rèn)適配器功能是將異步請求響應(yīng)回調(diào)切換到主線程)
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
......
} else {
......
}
}
默認(rèn)的DefaultCallAdapterFactory
請求適配器創(chuàng)建工廠源碼如下:
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
//如果是Android 默認(rèn)傳入的是Platform.MainThreadExecutor實例(可以通過Retrofit配置修改)
DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
//返回值類型不為Call.class段磨,則返回null
if (getRawType(returnType) != Call.class) {
return null;
}
//檢查返回參數(shù)類型
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
//獲取Call<xxx>,xxx參數(shù)對應(yīng)的類型
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
//如果是Android耗绿,最終會調(diào)用到ExecutorCallbackCall里苹支,JAVA不做處理
return executor == null ? call : new ExecutorCallbackCall<>(executor, 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) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) { //切換線程(默認(rèn)是切換到主線程)
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
@Override
public boolean isExecuted() {
return delegate.isExecuted();
}
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
......
}
}
ServiceMehod.invoke(Object args)
接上一步,loadServiceMethod(method)
返回的是個HttpServerMethod
子類的實例误阻,invoke具體實現(xiàn)在HttpServerMethod
中债蜜,源碼如下:
@Override
final @Nullable ReturnT invoke(Object[] args) {
//創(chuàng)建OkHttpCall實例
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
//調(diào)用adapt方法,Java最終會調(diào)用到CallAdapted的adapt方法中(Kotlin類似稍微有點區(qū)別)究反,最終會調(diào)用callAdapter的adapt方法寻定,源碼如下
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
//callAdapter如上一步所述,默認(rèn)情況下Android平臺返回的是ExecutorCalbackCall(內(nèi)部默認(rèn)實現(xiàn)僅是將異步請求返回回調(diào)切回主線程)精耐,當(dāng)然我們可以通過配置callbackExecutor和新增自定義callAdapter的方式改變返回值或者默認(rèn)行為
return callAdapter.adapt(call);
}
}
2.2.2狼速、總結(jié)
1、loadServiceMethod(method).invoke(args);
調(diào)用結(jié)束卦停,默認(rèn)情況下返回的是一個OKHttpCall
的實例(Android 平臺返回的是ExecutorCalbackCall
向胡,它是OKHttpCall
實例的裝飾器,擴(kuò)展了OKHttpCall
異步請求回調(diào)處理邏輯)惊完。
2捷枯、可以通過Retrofit.Builder
的callbackExecutor方法
設(shè)置異步回調(diào)處理器的方式改變ExecutorCalbackCall
默認(rèn)切換異步請求回調(diào)至主線程的行為。
3专执、可以通過Retrofit.Builder
的addCallAdapterFactory
方法,新增適配器工廠郁油,改變和擴(kuò)展方法返回值以及方法執(zhí)行本股,異步請求回調(diào)線程切換等邏輯。
4桐腌、Retrofit+RxJava的模式拄显,就是通過上述3的方式,新增適配器工廠案站,從而達(dá)到改變方法返回值躬审,擴(kuò)展功能的目的。
2.3、發(fā)起網(wǎng)絡(luò)請求
接上面2.2邏輯承边,返回的是OkHttpCall
(Android平臺默認(rèn)ExecutorCalbackCall
僅僅是個裝飾器遭殉,最終方法調(diào)用也會調(diào)用到OkHttpCall
里面)
(如果新增了CallAdapter,改變了返回值博助,最終還是需要調(diào)用到OkHttpCall
方法來實現(xiàn)網(wǎng)絡(luò)請求险污,流程和默認(rèn)行為類似)
2.3.1、源碼
同步請求
Call.execute()
方法
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
//一個Call只能執(zhí)行一次富岳,否則拋出一次
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
//獲取okhttp3.Call實例蛔糯,通過callFactory和requestFactory創(chuàng)建
//最終會調(diào)用OkHttpClient.newCall(Request request)方法創(chuàng)建okhttp3.Call實例
call = getRawCall();
}
if (canceled) {
call.cancel();
}
//最終調(diào)用okhttp3.Call的execute方法發(fā)起同步請求
//parseResponse解析響應(yīng)數(shù)據(jù)
return parseResponse(call.execute());
}
2.3.2、異步請求
Call.enqueue(final Callback\<T> callback)
方法
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
//一個Call只能執(zhí)行一次請求
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//獲取okhttp3.Call實例窖式,通過callFactory和requestFactory創(chuàng)建
//最終會調(diào)用OkHttpClient.newCall(Request request)方法創(chuàng)建okhttp3.Call實例
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//調(diào)用okhttp3.Call的enqueue異步方法發(fā)起異步請求
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//解析響應(yīng)數(shù)據(jù)
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
//回調(diào)響應(yīng)數(shù)據(jù)解析結(jié)果
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
//回調(diào)失敗
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
解析數(shù)據(jù)
OkHttpCall.parseResponse(okhttp3.Response rawResponse)
方法
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// 刪除請求體主體數(shù)據(jù)蚁飒,以便后面使用無主體數(shù)據(jù)的Response傳遞響應(yīng)結(jié)果
rawResponse =
rawResponse
.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
//判斷請求狀態(tài)碼
if (code < 200 || code >= 300) {
//非200,請求失敗
try {
//緩存錯誤響應(yīng)主體數(shù)據(jù)
ResponseBody bufferedBody = Utils.buffer(rawBody);
//生成Retrofit的Response實例并返回
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
//204萝喘,205判斷響應(yīng)體沒有主體內(nèi)容淮逻,直接返回成功無數(shù)據(jù)的Retrofit.Response實例
return Response.success(null, rawResponse);
}
//使用Okio.buffer讀取響應(yīng)體主體數(shù)據(jù)到ExceptionCatchingResponseBody(ResponseBody的子類)實例中
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//解析主體數(shù)據(jù),返回我們需要的數(shù)據(jù)實體對象
T body = responseConverter.convert(catchingBody);
//返回成功有數(shù)據(jù)的Retrofit.Response實例
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
2.3.2蜒灰、總結(jié)
廣告請求最終會調(diào)用到
okhttp3.Call
的同步或者異步方法弦蹂。通過
OkHttpCall.parseResponse
方法解析okhttp3.Call
請求返回的okhttp3.Response
響應(yīng)數(shù)據(jù)。最后會調(diào)用responseConverter.convert
(轉(zhuǎn)換器的轉(zhuǎn)換方法)解析轉(zhuǎn)換不同的數(shù)據(jù)結(jié)構(gòu)强窖。可以通過
Retrofit.Builder
的addConverterFactory
的方法凸椿,新增數(shù)據(jù)轉(zhuǎn)換器,支持解析不同的數(shù)據(jù)結(jié)構(gòu)翅溺。解析數(shù)據(jù)之后脑漫,會將響應(yīng)結(jié)果,成功數(shù)據(jù)實體或者失敗數(shù)據(jù)包裝成
Retrofit.Response
的實例返回咙崎∮判遥可以通過Retrofit.Response
類的code()
或者isSuccessful()
方法判斷是否成功。通過body()
方法獲取請求成功狀態(tài)下的返回的數(shù)據(jù)實體(可能為空)褪猛。如果不新增ConverterFactory网杆,默認(rèn)情況只能返回
okhttp3.ResponseBody
類的對象實例。即Retrofit.Response.body()
獲取的實例只能是okhttp3.ResponseBody
類的對象(java8+也可以是Optional
)伊滋,同時定義接口方法的返回值實際參數(shù)類型只能是okhttp3.ResponseBody.class
碳却。
三、最后總結(jié)
Retrofit框架讓開發(fā)者可以通過接口注解的方式描述網(wǎng)絡(luò)請求笑旺,然后通過JDK動態(tài)代理的方式真正實現(xiàn)接口方法調(diào)用邏輯昼浦。方法的調(diào)用會對接口注解進(jìn)行解析,最后將網(wǎng)絡(luò)請求解析結(jié)果和相關(guān)配置封裝到
OkHttpCall
中筒主。OkHttpCall
調(diào)用方法開始網(wǎng)絡(luò)請求关噪,最終還是會調(diào)用okHttp3.call
類中的同步或者異步請求方法鸟蟹,實現(xiàn)真正的網(wǎng)絡(luò)請求(即網(wǎng)絡(luò)請求的實現(xiàn)還是通過OkHttp框架實現(xiàn)的)。CallAdapter
數(shù)據(jù)請求適配器是為了擴(kuò)展OkHttpCall
的功能使兔,最后還是會通過OkHttpCall
來組織網(wǎng)絡(luò)請求建钥。ConverAdapter
數(shù)據(jù)轉(zhuǎn)換器的作用是在請求成功之后,將數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換成我們想要是實體對象火诸。