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è)計,才得以使其如此方便地進行網(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ò)請求適配器工廠的集合,默認是 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); } } }
跟進 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)碼進行處理 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ò)請求接口實例過程的詳細內(nèi)容,更多關(guān)于Retrofit 網(wǎng)絡(luò)請求接口的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決Android Studio Gradle Metadata特別慢的問題
這篇文章主要介紹了解決Android Studio Gradle Metadata特別慢的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android Jetpack架構(gòu)中ViewModel接口暴露的不合理探究
這篇文章主要介紹了Android Jetpack架構(gòu)組件 ViewModel詳解,ViewModel類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)存在,ViewModel類旨在以注重生命周期的方式存儲和管理界面相關(guān)的數(shù)據(jù)。感興趣可以來學習一下2022-07-07ImageView的屬性android:scaleType的作用分析
本篇文章是對ImageView的屬性android:scaleType的作用進行了詳細的分析介紹,需要的朋友參考下2013-06-06Android實現(xiàn)仿淘寶購物車增加和減少商品數(shù)量功能demo示例
這篇文章主要介紹了Android實現(xiàn)仿淘寶購物車增加和減少商品數(shù)量功能,結(jié)合實例形式分析了Android實現(xiàn)的淘寶購物車商品數(shù)量變換與計算相關(guān)技巧,需要的朋友可以參考下2016-07-07Android在一個app中安裝并卸載另一個app的示例代碼
這篇文章主要介紹了Android在一個app中安裝并卸載另一個app的示例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03Android開發(fā)中Activity之間切換出現(xiàn)短暫黑屏的解決方法
這篇文章主要介紹了Android開發(fā)中Activity之間切換出現(xiàn)短暫黑屏的解決方法,較為詳細的分析了Android中Activity之間切換出現(xiàn)短暫黑屏的原因與解決方法,需要的朋友可以參考下2016-02-02Android App調(diào)試內(nèi)存泄露之Cursor篇
最近在工作中處理了一些內(nèi)存泄露的問題,在這個過程中我尤其發(fā)現(xiàn)了一些基本的問題反而忽略導致內(nèi)存泄露2012-11-11