Retrofit學(xué)習(xí)筆記

注:以下內(nèi)容為本人自己做(chao)的學(xué)習(xí)筆記,可能含有少兒不宜的誤導(dǎo)性內(nèi)容,學(xué)習(xí)Retrofit請看參考文章。。。
參考文章:http://www.itdecent.cn/p/0d919e54eef0
OkHttp使用:

//創(chuàng)建client對象
OkHttpClient client = new OkHttpClient();

//創(chuàng)建Request
Request request = new Request.Builder()
  .url(url)
  .build();

//執(zhí)行請求,獲取結(jié)果
client.newCall(request).enqueue(new Callback() {
  @override
  public void onFailure(Call call, IOException e) {
  }

  @override
  public void onResponse(Call call, Response response) throws IOException {
    content.setText(response.body().string());
  }
});

以上既是OkHttp的使用方法,使用OkHttp時需要自己處理多線程,開啟子線程發(fā)送請求,收到數(shù)據(jù)后需要使用Handler來更新UI。
放屁,OkHttp支持同步和異步兩種方式發(fā)送請求,execute及enqueue。

Retrofit使用:

//定義API接口
public interface APIService {
  @GET("/test.json")
  Call<Model> getResult();

  @GET("/search.json")
  Call<SearchResult> getResult();
}

//創(chuàng)建Retrofit
Retrofit retrofit = new Retrofit.Builder()
  .baseUrl(BASE_URL)
  .addConverterFactory(GsonConverterFactory.create())
  .client(new OkHttpClient())
  .build();

//獲取接口Service的代理對象
APIService apiService = retrofit.create(APIService.class);

//調(diào)用代理對象的方法獲取到Call對象(Call對象是對Request的一層封裝)
Call<Model> result = apiService.getResult();

//異步執(zhí)行請求
result.enqueue(new Callback<Model>() {
  @override
  public void onResponse(Response<Model> response, Retrofit retrofit) {
    content.setText(response.body().toString());
  }

  @override
  public void onFailure(Throwable t) {
    content.setText("error");
  }
});

單從代碼量來看,Retrofit并不比OkHttp需要寫的代碼少。之所以要對OkHttp做這樣的封裝,我覺得原因在于:
1.不需要知道什么是Request,什么是Client以及Call對象,閉著眼用就行。
2.把網(wǎng)絡(luò)接口統(tǒng)一封裝到一個接口類中,看上去更規(guī)整。
3.使用Annotation標(biāo)識請求類型和路徑,雖然我并不知道這么干有什么卵用,大家都說好才是真的好。

既然要分享框架,那就必須得看源碼。
創(chuàng)建API接口類和用Builder創(chuàng)建Retrofit不提也罷。直接看重點(diǎn):
APIService apiService = retrofit.create(APIService.class);
傳一個接口類進(jìn)去,返回一個實(shí)例給我。
厲害了。
其實(shí)也并沒那么神奇,我猜測這個方法是這樣的:傳一個接口進(jìn)去,里面用代碼創(chuàng)建一個類,實(shí)現(xiàn)我傳進(jìn)去的這個接口,把那個類的實(shí)例返回給我。
咦?用代碼創(chuàng)建類?對我這種白菜來說也是很新鮮的,用代碼寫代碼看上去也是屌屌的。
嘍一眼源碼

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(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, 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);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

關(guān)鍵當(dāng)然是在return那一句。咦,Proxy是個啥...

Java動態(tài)代理
先說說我是怎么理解代理的。作為年輕程序猿,大都非常老實(shí)本分加勤奮,不愿意卷入世俗紛爭,假裝與Boss談笑風(fēng)生。所以這個時候,就要給每一個程序猿配送一個解說員,由解說員去解決談笑風(fēng)生的事,程序猿專心寫好程序就行了。這個解說員就可以看做是一個代理,事實(shí)上,這個代理的目的就是把程序猿和Boss進(jìn)行解耦,讓Boss專心談笑風(fēng)生,程序猿專心寫程序。
然而事與愿違,小公司請不起那么多人當(dāng)解說員,所以就有了動態(tài)代理,也就是Leader。Leader在不出事兒的時候(編譯時)是喝茶的,一旦一個團(tuán)隊的某個程序猿出了問題(運(yùn)行時),Leader就會跳出來變身成該程序猿的解說員去與Boss談笑風(fēng)生。

扯完了蛋,來看看動態(tài)代理的代碼:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    //權(quán)限判斷等,忽略
    //生成代理類
    Class<?> cl = getProxyClass0(loader, intfs);
    //調(diào)用構(gòu)造器,生成實(shí)例
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        //各種異常處理
    }
}

看方法名就能看出來,此方法是用來new代理實(shí)例的。
有三個參數(shù):
1.ClassLoader,類加載器,用來加載這個類...算了其實(shí)我不懂,反正就是要這個參數(shù)拿去創(chuàng)建類的。
2.Class<?>[] interfaces,要繼承的接口數(shù)組,這個我懂。
3.InvocationHandler,祈禱處理器......這個是代理類要完成的任務(wù)的具體實(shí)現(xiàn)。
Class<?> cl = getProxyClass0(loader, intfs);
這行代碼創(chuàng)建了一個代理類,實(shí)現(xiàn)了傳進(jìn)去的接口。
return cons.newInstance(new Object[]{h});
這行代碼返回上面創(chuàng)建的Class的新的實(shí)例,順便把接收到的InvocationHandler傳了進(jìn)去。
跟Retrofit結(jié)合來看一下。還記得這句代碼吧:
RestApi restApi = retrofit.create(RestApi.class);
我們傳一個接口類進(jìn)去,再看一遍Retrofit的create:

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(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, 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);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

它拿到了我們傳進(jìn)去的接口類的ClassLoader作為創(chuàng)建動態(tài)代理方法的第一個參數(shù),新建一個Class數(shù)組承載我們傳進(jìn)去的接口,最后它自己寫了一個InvocationHandler傳進(jìn)去。
最終,動態(tài)代理的newProxyInstance返回一個包含InvocationHandler,實(shí)現(xiàn)了Retrofit傳進(jìn)去接口的APIService接口類的代理類實(shí)例給Retrofit(自己看著都累)。Retrofit再把這個代理類實(shí)例返給我們。
OK,上面回顧的是傳入一個接口類給Retrofit,Retrofit返回代理實(shí)例給我們的實(shí)現(xiàn)流程。這時候還剩一個磨人的小妖精,就是那個InvocationHandler究竟是干啥的。
要探究這個問題就得看看生成的動態(tài)代理類里面是什么樣子的了。
Class<?> cl = getProxyClass0(loader, intfs);
這句代碼就是用來生成代理類的,那么來看看getProxyClass這個方法里頭干了啥。

private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
     //一個代理類最多能夠?qū)崿F(xiàn)65535個接口
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    // 這里Proxy做了一次緩存,如果之前生成過這個Classloader和interfaces的代理類,那么這里直接返回

  //否則新生成類的字節(jié)碼文件
   byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces);
            try {
                    //將字節(jié)碼加載到JVM
                    proxyClass = defineClass0(loader, proxyName,
                    proxyClassFile, 0, proxyClassFile.length);
              }
        retrun proxyClass;
}

可以看到,最終是調(diào)用ProxyGenerator的generateProxyClass方法生成類的字節(jié)碼并加載到JVM,再返回。
至于這個方法是怎么生成的,咱就不追下去了(因?yàn)閰⒖嫉奈恼吕餂]追...)。不過可以通過它生成的代理類反推它干了什么。
把生成的代理類的Class文件導(dǎo)出并反編譯,可以看到,這個代理類繼承自Proxy,實(shí)現(xiàn)了傳進(jìn)去的所有接口。它除了實(shí)現(xiàn)了Object基礎(chǔ)的equals,toString和hashCode這幾個方法外,還實(shí)現(xiàn)了我們接口定義的方法。

//以下代碼純手打,不一定準(zhǔn)確
public final Call<Model> getResult() throws {
  try {
    return (Call)super.h.invoke(this, m3, new Object[]{"retrofit"});
    } catch (RuntimeException | Error var4) {
        throw var4;
    } catch (Throwable var5) {
        throw new UndeclaredThrowableException(var5);
    }
}

其中,m3是通過反射拿到的Method對象。

private static Method m3;
m3 = Class.forName("proxy.GenerateClass$APIService").getMethod("getResult", new Class[] {});

我們拿到接口的動態(tài)代理實(shí)例后,直接調(diào)用動態(tài)代理中實(shí)現(xiàn)的我們的接口定義的getResult方法,此方法會把調(diào)用轉(zhuǎn)發(fā)給父類(Proxy)的InvocationHandler的invoke方法。
Call<Model> result = apiService.getResult();
此時Retrofit的create方法中的InvocationHandler的invoke回調(diào)被調(diào)用。

@Override 
public Object invoke(Object proxy, Method method, Object... args)
              throws Throwable {
  // 如果method是Object的基礎(chǔ)方法,就正常執(zhí)行方法
  if (method.getDeclaringClass() == Object.class) {
    return method.invoke(this, args);
  }
  //據(jù)說是Java8兼容,忽略
  if (platform.isDefaultMethod(method)) {
    return platform.invokeDefaultMethod(method, service, proxy, args);
  }
  ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
  OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
  return serviceMethod.callAdapter.adapt(okHttpCall);
  }
}

現(xiàn)在來看invoke回調(diào)。重點(diǎn)在最后三行代碼。
進(jìn)到ServiceMethod類中,看見注釋:
/** Adapts an invocation of an interface method into an HTTP call. */
翻譯一下就是說:把一個接口方法的invocation翻譯(適配)成一個HTTP 請求??梢灾苯永斫鉃椋篠erviceMethod把我們定義在APIService接口類中的方法翻譯成一個HTTP請求。具體就是翻譯接口類方法的注釋、參數(shù),然后自動加上什么Header啦,body啦的什么鬼。

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

從這個方法可以看出來,每一個method對應(yīng)一個serviceMethod。
所以第一行代碼就是獲取到當(dāng)前method對應(yīng)的serviceMethod。
第二行代碼
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
這里是Retrofit封裝Call對象的OkHttpCall類。它的構(gòu)造函數(shù)可以接受一個serviceMethod和參數(shù)。
第三行代碼
return serviceMethod.callAdapter.adapt(okHttpCall);
不用說,肯定是把okHttpCall變成Call對象返回給我們。這里Retrofit留了拓展可能性。這里的callAdapter由CallAdapter.Factory生產(chǎn),默認(rèn)使用的是DefaultCallAdapterFactory。我們可以對其進(jìn)行定制,自定義一個CallAdapter.Factory的子類,然后返回其他的類型。

到現(xiàn)在為止,終于把Retrofit的create方法走完了。再看一遍這個方法回憶一下整個流程吧。

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(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, 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);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

其實(shí)也沒那么復(fù)雜...
再往回套一層,回到使用上面來,咱們已經(jīng)調(diào)用了動態(tài)代理實(shí)例的方法,拿到了Call對象。往下就是enqueue執(zhí)行了,這個是OkHttp的東西,在這里就不深究了。

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

相關(guān)閱讀更多精彩內(nèi)容

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