Android小知識-剖析Retrofit中的網路請求介面
本平臺的文章更新會有延遲,大家可以關注微信公眾號-顧林海,包括年底前會更新kotlin由淺入深系列教程,目前計劃在微信公眾號進行首發,如果大家想獲取最新教程,請關注微信公眾號,謝謝!
在前兩節《 ofollow,noindex">Android小知識-剖析Retrofit中靜態內部類Builder的三個方法 》和《 Android小知識-剖析Retrofit中的網路請求流程以及相關引數
》中介紹了一些成員變數的初始化工作,那麼本節就來介紹剖析Retrofit中的網路請求介面。
public interface NetworkInterface { @GET("news/newsDetail") Call<MyResponse> getNewsDetails(@QueryMap Map<String,String> map); }
進行網路請求前需要建立網路請求介面類,在上面定義為NetworkInterface介面,其中定義了一個接受網路請求資料的方法叫做getNewsDetail,返回型別是一個泛型Call,Call裡面的型別是MyResponse,MyResponse就是我們請求網路返回的資料型別,在getNewsDetail方法上添加了註解GET,表示網路請求是用GET方式來請求的,在註解GET中定義相對url地址,在Retrofit中,網路請求的URL分為兩部分,第一部分在建立Retrofit時通過baseUrl傳入http請求的基地址,第二部分就是上面註解GET後面定義的http請求的相對地址,兩者加起來就是完整的http請求地址。
private void initRetrofit() { Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://icould.glh/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); NetworkInterface networkInterface = retrofit.create(NetworkInterface.class); }
建立完網路請求介面後就可以通過Retrofit的create方法,把網路請求介面的Class物件傳遞進去,返回一個網路請求介面的代理類。
進入create方法:
public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } ... }
通過工具類Utils的validateServiceInterface方法對介面的位元組碼進行驗證,下面判斷validateEagerly標誌位,在《 Android小知識-剖析Retrofit中的網路請求流程以及相關引數 》介紹過這個標誌位,表示是否提前解析網路請求介面中的方法,如果validateEagerly為true,就會執行eagerlyValidateMethods方法。
進入eagerlyValidateMethods方法:
private void eagerlyValidateMethods(Class<?> service) { Platform platform = Platform.get(); for (Method method : service.getDeclaredMethods()) { if (!platform.isDefaultMethod(method)) { loadServiceMethod(method); } } }
在該方法先是獲取具體的平臺Platform,往下看是一個for迴圈,通過反射獲取網路請求介面中的方法並遍歷,在遍歷時判斷isDefaultMethod方法。
boolean isDefaultMethod(Method method) { return false; }
發現isDefaultMethod方法固定返回false,那麼上面的if判斷語句中就會執行loadServiceMethod方法。
進入loadServiceMethod方法:
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); ... }
loadServiceMethod方法返回一個ServiceMethod物件,在Retrofit中通過動態代理的方式將網路請求介面中的方法轉換成一個個http請求,這個ServiceMethod物件就是對應介面中的一個方法,對介面中的方法進行封裝。
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; ... }
在loadServiceMethod方法中一開始從serviceMethodCache集合獲取請求方法對應的ServiceMethod物件,serviceMethodCache是ConcurrentHashMap集合型別,是執行緒安全的Map集合,如果serviceMethodCache當中存在對應請求方法的ServiceMethod物件,就直接返回該物件。
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); ServiceMethod<?, ?> loadServiceMethod(Method method) { ... synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder<>(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
如果serviceMethodCache這個快取集合中沒有對應方法的ServiceMethod物件,那麼就會利用Builder模式重新建立ServiceMethod物件,並將這個ServiceMethod物件儲存在serviceMethodCache這個快取集合中。
繼續回到Retrofit的create方法中:
public <T> T create(final Class<T> service) { ... return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ... ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.adapt(okHttpCall); } }); }
可以看到create方法返回的是網路請求介面的動態代理物件,通過Proxy的newProxyInstance方法建立動態代理物件,當我們呼叫代理類方法時,就會執行InvocationHandler的invoke方法。
整個Retrofit的核心就是InvocationHandler的invoke方法中的三行程式碼,後面一節會對這三個核心程式碼進行講解。

838794-506ddad529df4cd4.webp.jpg
搜尋微信“顧林海”公眾號,定期推送優質文章。