Android Retrofit原理深入探索
序章
首先引入依賴
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
在原理之前,我們先來回憶一下Retrofit的基本使用
1、定義接口
interface MyService {
@GET("gallery/{imageType}/response")
fun getImages(@Path("imageType") imageType: String): Call<List<String>>
}
2、構(gòu)建Retrofit,創(chuàng)建網(wǎng)絡(luò)請求接口類實例
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.build()
val myService = retrofit.create(MyService::class.java)
3、生成Call,執(zhí)行請求
val resp = myService.getImages("banner")
resp.enqueue(object : Callback<List<String>> {
override fun onResponse(call: Call<List<String>>, response: Response<List<String>>) {
TODO("Not yet implemented")
}
override fun onFailure(call: Call<List<String>>, t: Throwable) {
TODO("Not yet implemented")
}
})這樣一個基本的網(wǎng)絡(luò)請求就搞定了,使用很簡潔,正是因為其內(nèi)部使用了大量的設(shè)計模式和優(yōu)秀的架構(gòu)設(shè)計,才得以使其如此方便地進(jìn)行網(wǎng)絡(luò)請求,下面我們就一起來探索探索Retrofit的設(shè)計之美。
Retrofit構(gòu)建過程
使用了建造者模式通過內(nèi)部靜態(tài)類Builder構(gòu)建一個Retrofit實例,這里只列出了部分方法,其他類似
public static final class Builder {
private final Platform platform;
// 網(wǎng)絡(luò)請求工廠,工廠方法模式
private @Nullable okhttp3.Call.Factory callFactory;
// 網(wǎng)絡(luò)請求地址
private @Nullable HttpUrl baseUrl;
// 數(shù)據(jù)轉(zhuǎn)換器工廠的集合
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// 網(wǎng)絡(luò)請求適配器工廠的集合,默認(rèn)是ExecutorCallAdapterFactory
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
// 回調(diào)方法執(zhí)行器,用于切換線程
private @Nullable Executor callbackExecutor;
// 一個開關(guān),為true則會緩存創(chuàng)建的ServiceMethod
private boolean validateEagerly;
//......
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
// 將一個含有Gson對象實例的GsonConverterFactory放入數(shù)據(jù)轉(zhuǎn)換器工廠
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
//......
}通過build,我們上面Builder類中的參數(shù)對象都配置到了Retrofit對象中。
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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// 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());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}創(chuàng)建網(wǎng)絡(luò)請求接口實例過程
使用動態(tài)代理的方式拿到所有注解配置后,創(chuàng)建網(wǎng)絡(luò)請求接口實例。
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
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 {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}跟蹤 loadServiceMethod,parseAnnotations解析注解配置得到ServiceMethod,然后加入到serviceMethodCache緩存中,是一個ConcurrentHashMap。
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;
}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.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}執(zhí)行請求過程
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
// 創(chuàng)建一個OkHttp的Request對象請求
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
// 解析網(wǎng)絡(luò)請求返回的數(shù)據(jù)
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
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) {
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
}
}
});
} Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse =
rawResponse
.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
// 根據(jù)響應(yīng)返回的狀態(tài)碼進(jìn)行處理
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
// 將響應(yīng)體轉(zhuǎn)為Java對象
T body = responseConverter.convert(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;
}
}總結(jié)
首先,使用建造者模式通過Builder構(gòu)建一個Retrofit實例,Builder類中的參數(shù)對象都配置到Retrofit對象中,然后使用動態(tài)代理的方式拿到所有注解配置后,創(chuàng)建網(wǎng)絡(luò)請求接口實例,生成OkHttp請求,通過callAdapterFactory找到對應(yīng)的執(zhí)行器,比如RxJava2CallAdapterFactory,最后通過ConverterFactory將返回數(shù)據(jù)解析成JavaBean,使用者只需關(guān)心請求參數(shù),內(nèi)部實現(xiàn)由Retrofit封裝完成,底層請求還是基于okhttp實現(xiàn)的。
到此這篇關(guān)于Android Retrofit原理深入探索的文章就介紹到這了,更多相關(guān)Android Retrofit內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入學(xué)習(xí)Kotlin?枚舉的簡潔又高效進(jìn)階用法
這篇文章主要為大家介紹了深入學(xué)習(xí)Kotlin?枚舉簡潔又高效的進(jìn)階用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
AndroidStudio圖片壓縮工具ImgCompressPlugin使用實例
這篇文章主要為大家介紹了AndroidStudio圖片壓縮工具ImgCompressPlugin使用實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Android使用AlertDialog實現(xiàn)的信息列表單選、多選對話框功能
在使用AlertDialog實現(xiàn)單選和多選對話框時,分別設(shè)置setSingleChoiceItems()和setMultiChoiceItems()函數(shù)。具體實現(xiàn)代碼大家參考下本文吧2017-03-03
Bootstrap 下拉菜單.dropdown的具體使用方法
這篇文章主要介紹了Bootstrap 下拉菜單.dropdown的具體使用方法,詳細(xì)講解下拉菜單的交互,有興趣的可以了解一下2017-10-10
Android Activity啟動模式之singleTask實例詳解
這篇文章主要介紹了Android Activity啟動模式之singleTask,結(jié)合實例形式較為詳細(xì)的分析了singleTask模式的功能、使用方法與相關(guān)注意事項,需要的朋友可以參考下2016-01-01
詳解Android USB轉(zhuǎn)串口通信開發(fā)基本流程
本篇文章主要介紹了Android USB轉(zhuǎn)串口通信開發(fā)基本流程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
Android編輯框EditText與焦點變更監(jiān)視器及文本變化監(jiān)視器實現(xiàn)流程詳解
這篇文章主要介紹了Android編輯框EditText與焦點變更監(jiān)視器及文本變化監(jiān)視器實現(xiàn)流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-09-09

