Android每周一輪子:Retrofit

前言

充足的時(shí)間才是第一生產(chǎn)力。當(dāng)源碼看多了之后,對(duì)于很多點(diǎn)的梳理上可能就不會(huì)像之前那樣更具體了,本篇主要還是在于對(duì)實(shí)現(xiàn)主流程的分析。Retrofit在之前項(xiàng)目中并沒(méi)有用到過(guò),這次決定來(lái)看一些Retrofit相關(guān)實(shí)現(xiàn)來(lái)了解其中的原理。對(duì)于想要了解Java中的動(dòng)態(tài)代理應(yīng)用,想要用更簡(jiǎn)潔的方式實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求,Retrofit可能是最好的學(xué)習(xí)案例了,之前的項(xiàng)目中在寫(xiě)網(wǎng)絡(luò)請(qǐng)求的時(shí)候,每次都需要寫(xiě)大量的樣板代碼來(lái)構(gòu)造出一個(gè)網(wǎng)絡(luò)請(qǐng)求,代碼一旦增加,犯錯(cuò)誤的概率也就會(huì)增加,維護(hù)成本也就增加,同時(shí)也降低了開(kāi)發(fā)效率,工程化最佳實(shí)踐的目標(biāo)是讓開(kāi)發(fā)者只專(zhuān)注于自己的業(yè)務(wù)邏輯,而不需要關(guān)心下層具體的實(shí)現(xiàn),盡可能暴露少的業(yè)務(wù)無(wú)關(guān)的內(nèi)容給到上層。

基礎(chǔ)使用

對(duì)于Retrofit需要定義一個(gè)接口類(lèi),聲明要請(qǐng)求的接口和其中參數(shù)的傳遞方式,然后通過(guò)調(diào)用create方法就可以構(gòu)造一個(gè)Service類(lèi),調(diào)用相應(yīng)的方法即可幫助我們進(jìn)行網(wǎng)絡(luò)請(qǐng)求的發(fā)送,代碼非常簡(jiǎn)潔,同時(shí)我們也可以通過(guò)對(duì)不同的業(yè)務(wù)模塊分Service的方式來(lái)實(shí)現(xiàn)對(duì)于不同業(yè)務(wù)接口的隔離。

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

GitHubService service = retrofit.create(GitHubService.class);

源碼分析

Retrofit實(shí)例的創(chuàng)建是主要是進(jìn)行一些信息的配置,這里核心分析的在于其create方法,本篇文章的分析將會(huì)順著create方法的實(shí)現(xiàn)到其最終一個(gè)網(wǎng)絡(luò)請(qǐng)求的調(diào)用,同時(shí)結(jié)合著對(duì)Retrofit源碼的分析來(lái)進(jìn)一步展開(kāi)對(duì)于Java中動(dòng)態(tài)代理實(shí)現(xiàn)的分析。

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];
        //對(duì)于代理中的繼承自O(shè)bject的方法還有平臺(tái)方法直接invoke執(zhí)行
        @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);
        }
        if (platform.isDefaultMethod(method)) {
          return platform.invokeDefaultMethod(method, service, proxy, args);
        }
        //對(duì)于其它我們定義的方式調(diào)用loadServiceMethod
        return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
      }
    });
}

在Retrofit的實(shí)現(xiàn)中create是一個(gè)很關(guān)鍵的方法,也是我們作為源碼分析的一個(gè)切入點(diǎn)。首先看其第一個(gè)方法validateServiceInterface,該方法主要對(duì)傳遞的Service類(lèi)進(jìn)行校驗(yàn),同時(shí)通過(guò)對(duì)注解的處理來(lái)獲取到其中定義方法的相關(guān)信息。具體核心實(shí)現(xiàn)如下。

for (Method method : service.getDeclaredMethods()) {
    if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        loadServiceMethod(method);
    }
}

對(duì)于service中定義的方法進(jìn)行遍歷,然后通過(guò)調(diào)用loadServcieMethod進(jìn)行相應(yīng)的處理

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;
}

loadServiceMethod方法是Retrofit的整個(gè)框架的實(shí)現(xiàn)的一個(gè)很核心的點(diǎn)了,首先會(huì)從ServiceMethodCache中進(jìn)行相應(yīng)的查找,如果查找到則直接返回,沒(méi)有的話(huà)則會(huì)調(diào)用ServiceMethod的注解處理方法,parseAnnotaion來(lái)生成一個(gè)ServiceMethod,同時(shí)將其加入到緩存之中。那么接下來(lái),我們來(lái)看一下ServiceMethod的相關(guān)實(shí)現(xiàn),和其注解解析方法。

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);
}

這里的核心實(shí)現(xiàn)在RequestFactory的parseAnnoations和HttpServiceMethod的parseAnnotations方法。接下我們RequestFactory只是通過(guò)retorift和method構(gòu)建了一個(gè)RequestFactory,記錄了方法的參數(shù),返回值類(lèi)型還有注解信息。最后將其作為參數(shù)傳遞至HttpServiceMethod中的parseAnnotations,對(duì)于注解的處理主要是來(lái)將我們?cè)诎l(fā)送網(wǎng)絡(luò)請(qǐng)求時(shí)需要的信息從注解中解析出來(lái),當(dāng)調(diào)用invoke方法的時(shí)候,結(jié)合解析出來(lái)的參數(shù)構(gòu)建一個(gè)網(wǎng)絡(luò)請(qǐng)求。

final ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
}

在動(dòng)態(tài)代理中當(dāng)我們進(jìn)行一個(gè)方法調(diào)用的時(shí)候?qū)嶋H執(zhí)行代碼如下

loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

對(duì)于loadServiceMethod方法,我們之前已經(jīng)分析過(guò),這里主要根據(jù)方法解析的緩存中查找,然后調(diào)用其invoke方法,來(lái)構(gòu)造一個(gè)OkHttp的請(qǐng)求。然后調(diào)用okhttp的相應(yīng)的請(qǐng)求方法。

總結(jié)

image

對(duì)于Rerofit在項(xiàng)目中的使用,最上層是我們的業(yè)務(wù)邏輯,下面是我們針對(duì)每一個(gè)業(yè)務(wù)邏輯模塊定義的API,第三層是Retrofit對(duì)于API層向網(wǎng)絡(luò)請(qǐng)求OKhttp層的橋接,最終通過(guò)OkHttp將請(qǐng)求發(fā)送出去。同時(shí)其借助于注解與動(dòng)態(tài)代理讓代碼的實(shí)現(xiàn)變的更優(yōu)雅。借助于接口的形式來(lái)很好的實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求在業(yè)務(wù)層的隔離。注解與動(dòng)態(tài)代理搭配的形式對(duì)于后續(xù)的開(kāi)發(fā)設(shè)計(jì)也是很有啟發(fā)意義的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容