Retrofit 創(chuàng)建網(wǎng)絡(luò)請求接口實例過程
Retrofit 基本使用
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
interface NetApi {
@GET("/hotkey/json")
fun getHotKey(): Call<Response>
companion object {
private const val BASE_URL = "https://www.wanandroid.com/"
fun createApi(): NetApi =
Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create())
.build().create(NetApi::class.java)
}
}
data class HotWords(
val id: String,
val name: String,
)
data class Response(
val errorCode: Int,
val errorMsg: String,
val data: List<HotWords>
)
NetApi.createApi().getHotKey().enqueue(object : Callback<Response> {
override fun onResponse(call: Call<Response>, response: retrofit2.Response<Response>) {
Log.i(tag, "onResponse: ${response.body()?.data}")
}
override fun onFailure(call: Call<Response>, t: Throwable) {
Log.i(tag, "onFailure: ${t.message}")
}
})
這樣一個基本的網(wǎng)絡(luò)請求就搞定了,使用很簡潔,正是因為其內(nèi)部使用了大量的設(shè)計模式和優(yōu)秀的架構(gòu)設(shè)計,才得以使其如此方便地進(jìn)行網(wǎng)絡(luò)請求,下面來一起瞧瞧 Retrofit 的源碼吧~
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
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;
}
parseAnnotations 解析注解配置得到 ServiceMethod,然后加入到 serviceMethodCache 緩存中,是一個 ConcurrentHashMap 。
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);
}
通過 RequestFactory 的 parseAnnotations 方法,解析接口方法上的注解,然后封裝在 RequestFactory 對象中,將其返回,這個 RequestFactory,主要用于后續(xù)創(chuàng)建 OkHttp 請求所需要的 Request 對象。那后面的 HttpServiceMethod.parseAnnotations 又是干什么的呢?往下看。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
如果不是 kotlin suspend 函數(shù),使用 CallAdapted 類,如果是 kotlin suspend 函數(shù)返回類型是 Response,則使用 SuspendForResponse 類,其余情況使用 SuspendForBody,如 suspend 函數(shù)返回類型不是 Response 。一般情況下,我們使用的基本上是屬于其余情況,我們來看下 SuspendForBody 類
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
private final boolean isNullable;
...
@Override
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
try {
return isNullable
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
}
跟進(jìn) KotlinExtensions.awaitNullable,我們可以看到 SuspendForBody 會將 Response.body 作為協(xié)程掛起點的返回值。
suspend fun <T : Any> Call<T?>.await(): T? {
return suspendCancellableCoroutine { continuation ->
//協(xié)程取消是調(diào)用 cancel
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T?> {
override fun onResponse(call: Call<T?>, response: Response<T?>) {
if (response.isSuccessful) {
//繼續(xù)執(zhí)行相應(yīng)的協(xié)程,將 response.body 作為最后一個掛起點的返回值。
continuation.resume(response.body())
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T?>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
執(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 的 Call 對象
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);
}
//包裝 RequestBody
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 對象中,然后使用 JDK 動態(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)的。
以上就是Retrofit 創(chuàng)建網(wǎng)絡(luò)請求接口實例過程的詳細(xì)內(nèi)容,更多關(guān)于Retrofit 網(wǎng)絡(luò)請求接口的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決Android Studio Gradle Metadata特別慢的問題
這篇文章主要介紹了解決Android Studio Gradle Metadata特別慢的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android Jetpack架構(gòu)中ViewModel接口暴露的不合理探究
這篇文章主要介紹了Android Jetpack架構(gòu)組件 ViewModel詳解,ViewModel類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)存在,ViewModel類旨在以注重生命周期的方式存儲和管理界面相關(guān)的數(shù)據(jù)。感興趣可以來學(xué)習(xí)一下2022-07-07
ImageView的屬性android:scaleType的作用分析
本篇文章是對ImageView的屬性android:scaleType的作用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Android實現(xiàn)仿淘寶購物車增加和減少商品數(shù)量功能demo示例
這篇文章主要介紹了Android實現(xiàn)仿淘寶購物車增加和減少商品數(shù)量功能,結(jié)合實例形式分析了Android實現(xiàn)的淘寶購物車商品數(shù)量變換與計算相關(guān)技巧,需要的朋友可以參考下2016-07-07
Android在一個app中安裝并卸載另一個app的示例代碼
這篇文章主要介紹了Android在一個app中安裝并卸載另一個app的示例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03
Android開發(fā)中Activity之間切換出現(xiàn)短暫黑屏的解決方法
這篇文章主要介紹了Android開發(fā)中Activity之間切換出現(xiàn)短暫黑屏的解決方法,較為詳細(xì)的分析了Android中Activity之間切換出現(xiàn)短暫黑屏的原因與解決方法,需要的朋友可以參考下2016-02-02
Android App調(diào)試內(nèi)存泄露之Cursor篇
最近在工作中處理了一些內(nèi)存泄露的問題,在這個過程中我尤其發(fā)現(xiàn)了一些基本的問題反而忽略導(dǎo)致內(nèi)存泄露2012-11-11

