Retrofit 創(chuàng)建網絡請求接口實例過程
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}") } })
這樣一個基本的網絡請求就搞定了,使用很簡潔,正是因為其內部使用了大量的設計模式和優(yōu)秀的架構設計,才得以使其如此方便地進行網絡請求,下面來一起瞧瞧 Retrofit 的源碼吧~
Retrofit構建過程
使用了建造者模式通過內部靜態(tài)類 Builder 構建一個 Retrofit 實例,這里列出了部分方法,其他類似。
public static final class Builder { private final Platform platform; // 網絡請求工廠,工廠方法模式 private @Nullable okhttp3.Call.Factory callFactory; // 網絡請求地址 private @Nullable HttpUrl baseUrl; // 數(shù)據(jù)轉換器工廠的集合 private final List<Converter.Factory> converterFactories = new ArrayList<>(); // 網絡請求適配器工廠的集合,默認是 ExecutorCallAdapterFactory private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); // 回調方法執(zhí)行器,用于切換線程 private @Nullable Executor callbackExecutor; // 一個開關,為 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ù)轉換器工廠 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)建網絡請求接口實例過程
使用動態(tài)代理的方式拿到所有注解配置后,創(chuàng)建網絡請求接口實例。
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é)程取消是調用 cancel continuation.invokeOnCancellation { cancel() } enqueue(object : Callback<T?> { override fun onResponse(call: Call<T?>, response: Response<T?>) { if (response.isSuccessful) { //繼續(xù)執(zhí)行相應的協(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 { // 解析網絡請求返回的數(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ù)響應返回的狀態(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 { // 將響應體轉為 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; } }
總結
使用建造者模式通過 Builder 構建一個 Retrofit 實例,Builder 類中的參數(shù)對象都配置到 Retrofit 對象中,然后使用 JDK 動態(tài)代理的方式拿到所有注解配置后,創(chuàng)建網絡請求接口實例,生成 OkHttp 請求,通過 CallAdapterFactory 找到對應的執(zhí)行器,比如 RxJava2CallAdapterFactory,通過 ConverterFactory 將返回數(shù)據(jù)解析成 JavaBean,使用者只需關心請求參數(shù),內部實現(xiàn)由 Retrofit 封裝完成,底層請求還是基于 Okhttp 實現(xiàn)的。
以上就是Retrofit 創(chuàng)建網絡請求接口實例過程的詳細內容,更多關于Retrofit 網絡請求接口的資料請關注腳本之家其它相關文章!
相關文章
解決Android Studio Gradle Metadata特別慢的問題
這篇文章主要介紹了解決Android Studio Gradle Metadata特別慢的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android Jetpack架構中ViewModel接口暴露的不合理探究
這篇文章主要介紹了Android Jetpack架構組件 ViewModel詳解,ViewModel類讓數(shù)據(jù)可在發(fā)生屏幕旋轉等配置更改后繼續(xù)存在,ViewModel類旨在以注重生命周期的方式存儲和管理界面相關的數(shù)據(jù)。感興趣可以來學習一下2022-07-07ImageView的屬性android:scaleType的作用分析
本篇文章是對ImageView的屬性android:scaleType的作用進行了詳細的分析介紹,需要的朋友參考下2013-06-06Android實現(xiàn)仿淘寶購物車增加和減少商品數(shù)量功能demo示例
這篇文章主要介紹了Android實現(xiàn)仿淘寶購物車增加和減少商品數(shù)量功能,結合實例形式分析了Android實現(xiàn)的淘寶購物車商品數(shù)量變換與計算相關技巧,需要的朋友可以參考下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-02