從問題到解析蚜印,讀懂Retrofit2原理

在項(xiàng)目開發(fā)中其實(shí)最常見的網(wǎng)絡(luò)請(qǐng)求框架就是OkHttp+Retrofit铃岔,在上一篇老生新談牲距,從OkHttp原理看網(wǎng)絡(luò)請(qǐng)求剖析了OkHttp的原理,今天這篇文章將從不同的角度來看Retrofit的內(nèi)部實(shí)現(xiàn)逢净。

讀完這篇文章,您將了解到:

  • 什么是動(dòng)態(tài)代理模式歼指?
  • Retrofit為什么要使用動(dòng)態(tài)代理爹土?
  • Retrofit如何與OkHttp相結(jié)合?
  • Retrofit是如何將子線程切換到主線程踩身?
  • Retrofit彌補(bǔ)了OkHttp的哪些缺點(diǎn)胀茵?

以下源碼版本為retrofit:2.9.0

什么是動(dòng)態(tài)代理?

在Retrofit源碼分析之前需要了解的一個(gè)比較重要的點(diǎn)挟阻,就是動(dòng)態(tài)代理模式琼娘,它是Retrofit的核心設(shè)計(jì)的開始。

動(dòng)態(tài)代理和靜態(tài)代理都屬于代理模式附鸽,動(dòng)態(tài)代理是可以在運(yùn)行期動(dòng)態(tài)創(chuàng)建某個(gè)interface的實(shí)例脱拼,我們通過Proxy.newProxyInstance產(chǎn)生的代理類,當(dāng)調(diào)用接口的任何方法時(shí)坷备,都會(huì)被InvocationHandler#invoke方法攔截熄浓,同時(shí),在這個(gè)方法中可以拿到所傳入的參數(shù)等省撑,依照參數(shù)值再做相應(yīng)的處理赌蔑。

定義比較抽象,舉個(gè)普通的例子竟秫。

例如某用戶近期需要購房娃惯,那么他就需要委托中介幫忙推薦房源,之后買家通過中介與開發(fā)商達(dá)成買賣協(xié)議肥败。這里的中介就是代理對(duì)象趾浅,買家則是委托者,而其中“推薦房源”這件事情拙吉,則是抽象對(duì)象潮孽,也是委托者真正需要做的動(dòng)作。

看下偽代碼筷黔,首先定義委托者想要做的動(dòng)作往史,并且告訴中介我對(duì)房子的一些基本要求:

/**
 * 買家委托中介購房。
 */
interface ToDo {
    fun buyHouse()
}

定義代理對(duì)象佛舱,即中介椎例,并實(shí)現(xiàn)InvocationHandler挨决,根據(jù)委托者的要求點(diǎn)返回代理對(duì)象:

/**
 * 中介
 */
class Middlemen(private val any: Any) : InvocationHandler {
    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
        return method?.invoke(any, *(args ?: arrayOfNulls<Any>(0)))
    }
}

委托者告訴中介,我要購房的信息:

/**
 * 買家
 */
class Buyer : ToDo {
    override fun buyHouse() {
        print("中介订歪,請(qǐng)幫我買房子")
    }
}

最后利用代理對(duì)象實(shí)現(xiàn)購房的動(dòng)作:

fun main(args: Array<String>) {
        val toDo: ToDo = Buyer()
        val dynamicMid = Proxy.newProxyInstance(
            toDo.javaClass.classLoader, toDo.javaClass.interfaces,
            Middlemen(toDo)
        ) as ToDo
        dynamicMid.buyHouse()
    }

動(dòng)態(tài)代理最主要的部分在于代理對(duì)象實(shí)現(xiàn)InvocationHandler脖祈,并重寫invoke方法。 當(dāng)代理對(duì)象代理了委托者的要求刷晋,不管要求有多少盖高,當(dāng)代理執(zhí)行時(shí),都會(huì)走進(jìn)invoke()方法中眼虱。這是重點(diǎn)喻奥,圈起來后面要考。

我們應(yīng)該了解到捏悬,Retrofit的核心部分就在這動(dòng)態(tài)代理中撞蚕,那Retrofit為什么要使用動(dòng)態(tài)代理?且動(dòng)態(tài)代理中又做了哪些動(dòng)作过牙? ??

那就接著往下分析源碼甥厦。

源碼解析

在源碼分析之前,有兩個(gè)重要的對(duì)象需要提前說明寇钉,提前了解他們的作用刀疙,更有利于后續(xù)的源碼解讀。

一個(gè)是CallAdapter扫倡,另外則是Converter庙洼。

  • CallAdapter: 適配器,我們默認(rèn)定義API Service方法的返回值為Call<T>類型镊辕,但是有時(shí)候會(huì)自定義返回類型油够,例如和RxJava相結(jié)合,返回Observable或者Single類型的時(shí)候應(yīng)該怎么處理征懈?CallAdapter的作用就是幫助開發(fā)者去適配這些返回類型石咬,你定義了什么類型的數(shù)據(jù),就可以通過CallAdapter#adapt進(jìn)行返回卖哎。
  • Converter: 數(shù)據(jù)裝換器鬼悠,主要負(fù)責(zé)把服務(wù)器返回的數(shù)據(jù)ResponseBody轉(zhuǎn)化為 T 類型的對(duì)象。例如在使用retrofit進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí)亏娜,我們都會(huì)先定義一個(gè)返回值的實(shí)體類焕窝,Converter就會(huì)將網(wǎng)絡(luò)請(qǐng)求的返回值轉(zhuǎn)換為我們所需要的類型。

CallAdapter和Converter的作用如上述所說维贺,接下來就直接進(jìn)入到retrofit的動(dòng)態(tài)代理源碼中它掂。

  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 {
                1??
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                2??
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

retrofit的創(chuàng)建在于retrofit.create(ApiService::class.java),內(nèi)部使用動(dòng)態(tài)代理模式,可以看到invoke方法中一開始就有幾個(gè)判斷:

  1. 1??判斷當(dāng)前方法是否是在接口中聲明虐秋,如果不是則直接按照正常流程調(diào)用invoke榕茧;
  2. 2??判斷是否屬于Android平臺(tái)的默認(rèn)方法,如果是則直接按照正常流程調(diào)用invoke客给,反之用押,則就到了動(dòng)態(tài)代理的核心部分:loadServiceMethod(method).invoke(args)

最后一行代碼主要分為兩步:loadServiceMethod(method)invoke(args)

loadServiceMethod(method)

這個(gè)方法的作用先提一下靶剑,它主要是將網(wǎng)絡(luò)請(qǐng)求方法中的信息進(jìn)行初步的處理蜻拨,我們?cè)趧?chuàng)建api service具體接口時(shí),會(huì)加上注解(@GET桩引,@POST官觅,@PUT...),參數(shù)(@Path阐污、@Query...)等,該方法就是對(duì)接口中的注解咱圆、參數(shù)等進(jìn)行解析笛辟,解析接口后又生成了一個(gè)RequestFactory請(qǐng)求工廠對(duì)象,并且利用這個(gè)RequestFactory對(duì)象創(chuàng)建了一個(gè)CallAdapter序苏。

invoke(args)

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

invoke的實(shí)現(xiàn)中也只有兩行代碼手幢。

第一行:主要利用loadServiceMethod所創(chuàng)建的RequestFactory以及一些轉(zhuǎn)換類作為參數(shù)生成一個(gè)OkHttpCall對(duì)象, OkHttpCall其實(shí)是對(duì)OkHttp中的realCall進(jìn)行了一層包裝(realCall可參考上一篇OkHttp的解析)忱详,
在Retrofit里围来,OkHttpCall緊密連接OkHttp,它的內(nèi)部同樣可以調(diào)用同步execute匈睁、 異步execute方法進(jìn)行網(wǎng)絡(luò)請(qǐng)求监透,其實(shí)真正調(diào)用的也就是OkHttp的execute和execute方法。在此同時(shí)航唆,Retrofit中會(huì)對(duì)請(qǐng)求響應(yīng)也做了解析胀蛮。

我們先來看看OkHttpCall中網(wǎng)絡(luò)請(qǐng)求的細(xì)節(jié):

  @Override
  public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");

    okhttp3.Call call;
    synchronized (this) {
      ...
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        }
      }
    ...
    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            try {
              //解析請(qǐng)求返回值
              response = parseResponse(rawResponse);
            }
              ...
            try {
              callback.onResponse(OkHttpCall.this, response);
            }

          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
            callFailure(e);
          }

          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            }
          }
        });
  }

以一個(gè)異步請(qǐng)求為例,

  1. 內(nèi)部首先調(diào)用了一個(gè)createRawCall()方法糯钙,創(chuàng)建rawCall粪狼,這個(gè)rawCall其實(shí)指代的就是Okhttp3的call,也就是OkHttp進(jìn)行網(wǎng)絡(luò)請(qǐng)求調(diào)用的一個(gè)調(diào)度器任岸;

  2. 創(chuàng)建好OkHttp的call后再榄,就開始調(diào)用enqueue進(jìn)行異步請(qǐng)求,發(fā)現(xiàn)在異步請(qǐng)求內(nèi)響應(yīng)的回調(diào)屬于okhttp3.Callback享潜,所返回來的結(jié)果困鸥,也都是okhttp3.Response,到這里就可以大概知道了剑按,retrofit的網(wǎng)絡(luò)請(qǐng)求其實(shí)還是由OkHttp來實(shí)現(xiàn)窝革。

  3. okhttp3.Response這個(gè)響應(yīng)不方便開發(fā)者直接使用购城,所以retrofit在收到結(jié)果后,又對(duì)響應(yīng)結(jié)果進(jìn)行新一輪的解析 response = parseResponse(rawResponse)虐译,以Response對(duì)象的形式返回給開發(fā)者瘪板。

另外還有最后一行: adapt(call, args); 它的內(nèi)部其實(shí)是由一個(gè)適配器CallAdapted來調(diào)用,如下:

  protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }

在源碼解析的一開始就對(duì)callAdapter進(jìn)行了定義漆诽,這里將詳細(xì)說明侮攀。

adapt是一個(gè)抽象方法,里面?zhèn)魅肓松厦鎰倓?chuàng)建的OkHttpCall作為參數(shù)厢拭。adapt即adapter兰英,適配器的意思,那我們可以猜測(cè)一下供鸠,傳入OkHttpCall畦贸,是不是就是為了對(duì)OkHttpCall再進(jìn)行適配的工作?但楞捂,OkHttpCall已經(jīng)可以進(jìn)行網(wǎng)絡(luò)請(qǐng)求了薄坏,為什么還需要使用CallAdapted進(jìn)行再次的適配呢? ??這個(gè)問題還是先記下寨闹,拋到后面解答胶坠。

咱們繼續(xù)來分析動(dòng)態(tài)代理的主線條,從上面分析知道繁堡,retrofit之所以調(diào)用簡(jiǎn)便沈善,是因?yàn)閮?nèi)部對(duì)@GET,@POST椭蹄,@Path等注解以及請(qǐng)求參數(shù)進(jìn)行了解析闻牡,讓開發(fā)者只需要關(guān)心自己新增的請(qǐng)求方法是不是符合規(guī)范。

而上述動(dòng)態(tài)代理最主要做的事情就是創(chuàng)建了CallAdapted绳矩,CallAdapted其實(shí)只是一個(gè)適配器澈侠,主要需要了解的是它適配的是什么? 是否還記得我們?cè)谏厦鎾伋隽艘粋€(gè)關(guān)于CallAdapted的問題:那就先來看看他是如何創(chuàng)建的埋酬???

CallAdapted

loadServiceMethod方法其實(shí)返回的就是CallAdapted對(duì)象哨啃,那我們就直奔主題,進(jìn)去瞧一瞧写妥,

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {

    Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType =
          Utils.getParameterLowerBound(
              0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }

    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
  ...

    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    }

跟蹤到最后拳球,是在HttpServiceMethod類中的parseAnnotations中發(fā)現(xiàn)了CallAdapted的創(chuàng)建..

public CallAdapter<?, ?> nextCallAdapter(
      @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

CallAdapter是根據(jù)returnType和annotations的類型,從callAdapterFactories工廠中進(jìn)行查找珍特,從而返回所對(duì)應(yīng)的網(wǎng)絡(luò)請(qǐng)求適配器祝峻,這里returnType指的是網(wǎng)絡(luò)請(qǐng)求接口里方法的返回值類型,如Call<?>、Observable<?>等莱找。annotations則指代的是注解類型酬姆,如@GET、@POST等奥溺。

這里也提到了一個(gè)適配器工廠callAdapterFactories辞色,不同的CallAdapter就是從這個(gè)工廠中查詢出來的,有查找那就必定有添加浮定,那適配器CallAdapter是怎么添加到工廠類中的相满? ??callAdapterFactories這個(gè)變量是屬于Retrofit類,跟蹤發(fā)現(xiàn)是由Retrofit構(gòu)造函數(shù)傳入桦卒,也就是Retrofit初始化時(shí)進(jìn)行了賦值立美。

Retrofit的初始化是由一種建造者模式來創(chuàng)建,在Retrofit的build()方法中方灾,找到了適配器工廠對(duì)其適配器的添加:

 public Retrofit build() {
     ...
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      //添加適配器callAdapter
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
     ...
      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }

platform.defaultCallAdapterFactories 指的是Android平臺(tái)的一個(gè)默認(rèn)的適配器工廠建蹄,當(dāng)我們不使用自定義適配器工廠時(shí),則添加的就是這默認(rèn)的工廠裕偿。這里提到了自定義適配器工廠洞慎,其實(shí)我們?cè)谑褂肦etrofit的時(shí)候,有時(shí)候會(huì)和RxJava結(jié)合击费,例如在創(chuàng)建Retrofit時(shí),也會(huì)addCallAdapterFactory桦他,將RxJava2CallAdapterFactory添加到callAdapterFactories中蔫巩。

   mRetrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(baseUrl)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();

添加調(diào)用適配器工廠的目的就是支持Call以外的服務(wù)方法返回類型,如支持Observable快压,Single返回類型等圆仔。 在callAdapterFactories集合器添加一個(gè)默認(rèn)適配器工廠時(shí),也附帶傳進(jìn)去了一個(gè)參數(shù)callbackExecutor蔫劣,callbackExecutor是Java8或者Android平臺(tái)的一個(gè)默認(rèn)線程調(diào)度器坪郭,它的作用涉及到一個(gè)線程切換的問題,也就是后續(xù)需要分析的retrofit是如何將子線程切換到主線程脉幢???

這個(gè)問題還是先記下歪沃,后面針對(duì)線程切換詳細(xì)說明。

在上面源碼創(chuàng)建CallAdapter時(shí)嫌松,有一個(gè)對(duì)象也同時(shí)被創(chuàng)建沪曙,那就是Converter

Converter

Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);

Converter在文章一開頭也說過萎羔,是數(shù)據(jù)裝換器液走。它的添加和獲取方式和CallAdapter類似。在Retrofit初始化時(shí)添加到List<Converter.Factory>工廠集合,例如與GSon結(jié)合時(shí)缘眶,addConverterFactory(GsonConverterFactory.create()

mRetrofit = new Retrofit.Builder()
                .client(mOkHttpClient)
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create()
                .build();

后面也根據(jù)類型Type取出不同的Converter嘱根,對(duì)返回的網(wǎng)絡(luò)響應(yīng),做出數(shù)據(jù)的轉(zhuǎn)換巷懈,例如轉(zhuǎn)換成實(shí)體類该抒。

基本邏輯與CallAdapter類似。

說了這么多砸喻,是不是有點(diǎn)思路了柔逼,我們先來捋一捋。

  1. 一開始動(dòng)態(tài)代理中調(diào)用loadServiceMethod方法割岛,解析接口方法中的注解愉适,參數(shù),頭部信息等癣漆;
  2. 依據(jù)接口方法的返回類型维咸,從適配器工廠集合里進(jìn)行查詢,生成相應(yīng)的適配器CallAdapter惠爽,區(qū)分是RxJava的Observable癌蓖、Single還是Call或者其他類型,(適配器工廠集合的數(shù)據(jù)是由構(gòu)建Retrofit時(shí)addCallAdapterFactory()添加婚肆,如無自定義租副,則添加Android平臺(tái)默認(rèn)適配器)。以相同的方式取出數(shù)據(jù)轉(zhuǎn)換器Converter较性;
  3. 利用上面生成的CallAdapter用僧,調(diào)用invoke方法,創(chuàng)建OkHttpCall對(duì)象赞咙,即針對(duì)請(qǐng)求信息责循,利用OkHttp進(jìn)行異步或者同步網(wǎng)絡(luò)請(qǐng)求,并且對(duì)響應(yīng)結(jié)果進(jìn)行實(shí)體類轉(zhuǎn)換攀操;
  4. 創(chuàng)建好OkHttpCall后院仿,又利用上面查詢到的適配器CallAdapter調(diào)用adapt,返回RxJava的Observable速和、Single或者Call對(duì)象歹垫。

在Retrofit初始化時(shí)有涉及到一個(gè)參數(shù)callbackExecutor,當(dāng)時(shí)拋出了一個(gè)問題:Retrofit是如何將子線程切換到主線程颠放?這里就來詳細(xì)看看县钥。

Retrofit是如何將子線程切換到主線程?

在添加默認(rèn)適配器工廠defaultCallAdapterFactories時(shí)慈迈,將callbackExecutor作為了一個(gè)參數(shù)若贮,那么它的具體實(shí)現(xiàn)也就是在這個(gè)默認(rèn)適配器工廠中省有。
我們來看下callbackExecutor在里面做了些啥。

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;
    ...

    @Override
    public void enqueue(final Callback<T> callback) {

      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // Emulate OkHttp's behavior of throwing/delivering an IOException on
                      // cancellation.
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }

在上述代碼里了解到谴麦,callbackExecutor即Executor蠢沿,一個(gè)線程調(diào)度器。在Call的enqueue實(shí)現(xiàn)里執(zhí)行了一個(gè)異步網(wǎng)絡(luò)請(qǐng)求delegate.enqueue匾效,在請(qǐng)求的響應(yīng)onResponse舷蟀、onFailure中
Executor也同樣執(zhí)行了一個(gè)線程,這里就有個(gè)疑問面哼,為什么要在一個(gè)異步請(qǐng)求里又調(diào)用一個(gè)線程野宜?我們知道callbackExecutor是一個(gè)線程調(diào)度器,那他內(nèi)部到底實(shí)現(xiàn)的是什么魔策?
默認(rèn)callbackExecutor的創(chuàng)建在Retrofit的初始化中匈子,callbackExecutor = platform.defaultCallbackExecutor();

static final class Android extends Platform {

    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}

platform是一個(gè)Android平臺(tái),defaultCallbackExecutor 內(nèi)部其實(shí)調(diào)用的是 new MainThreadExecutor() 闯袒,很清楚的看到虎敦, handler.post(r) 內(nèi)部使用Handler將響應(yīng)拋到了主線程。

這就是Retrofit將子線程切換到主線程的核心所在政敢。

Retrofit為什么要使用動(dòng)態(tài)代理其徙?

文章一開始就拋出了這個(gè)問題,經(jīng)過一輪分析后喷户,也就有了答案唾那。

我們想一下,動(dòng)態(tài)代理的優(yōu)勢(shì)是什么褪尝?是不是不用暴露真實(shí)的委托者闹获,根據(jù)不同的委托創(chuàng)建不同的代理,通過代理去做事情恼五。

那Retrofit彌補(bǔ)了OkHttp的缺點(diǎn)又指的是什么昌罩?OkHttp在使用的時(shí)候哭懈,請(qǐng)求參數(shù)的配置是不是很繁瑣灾馒,尤其當(dāng)有一些表單提交時(shí),又臭又長(zhǎng)遣总,而Retrofit就是彌補(bǔ)了這個(gè)缺點(diǎn)睬罗,利用@GET、@POST旭斥、@Path容达、@Body等注解以及一些參數(shù)很簡(jiǎn)便的就構(gòu)造出了請(qǐng)求。

當(dāng)Retrofit創(chuàng)建了不同的接口垂券,動(dòng)態(tài)代理就發(fā)揮出了作用花盐。每當(dāng)不同接口方法執(zhí)行時(shí)羡滑,動(dòng)態(tài)代理都會(huì)攔截該請(qǐng)求,對(duì)接口中的注解算芯,參數(shù)進(jìn)行解析柒昏,構(gòu)建出不同的Request,最后則交給OkHttp去真正執(zhí)行熙揍。

Retrofit結(jié)合動(dòng)態(tài)代理职祷,不用關(guān)心真正的接口方法,對(duì)符合規(guī)范的接口進(jìn)行統(tǒng)一化的管理届囚,以統(tǒng)一的方式解析注解和參數(shù)有梆,拼接成request。

總結(jié)

通過源碼以及問題的解答意系,了解到Retrofit其實(shí)是OkHttp的封裝類泥耀,內(nèi)部網(wǎng)絡(luò)請(qǐng)求還是靠的OkHttp,那Retrofit封裝后改變了什么昔字?

  • 接口請(qǐng)求更加簡(jiǎn)便爆袍,標(biāo)注注解@GET、@POST作郭、@Path陨囊、@Body等就形成一個(gè)網(wǎng)絡(luò)請(qǐng)求;
  • 默認(rèn)幫助開發(fā)者解析responseBody夹攒,另外還可以自定義解析策略蜘醋;
  • Retrofit幫助開發(fā)者進(jìn)行線程切換;
  • Retrofit帶給開發(fā)者更多的權(quán)限咏尝,可自定義適配網(wǎng)絡(luò)請(qǐng)求压语。

Retrofit源碼不多,但是卻包含了很多設(shè)計(jì)技巧编检,后續(xù)將開一篇詳細(xì)說明Retrofit的設(shè)計(jì)之美胎食。

以上便是Retrofit的源碼解析,希望這篇文章能幫到您允懂,感謝閱讀厕怜。

推薦閱讀

老生新談,從OkHttp原理看網(wǎng)絡(luò)請(qǐng)求
【網(wǎng)絡(luò)篇】開發(fā)必備知識(shí)點(diǎn):UDP/TCP協(xié)議

歡迎關(guān)注公 z 號(hào):9點(diǎn)大前端蕾总,每天9點(diǎn)推薦更多前端粥航、Android、Flutter文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末生百,一起剝皮案震驚了整個(gè)濱河市递雀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蚀浆,老刑警劉巖缀程,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搜吧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡杨凑,警方通過查閱死者的電腦和手機(jī)赎败,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蠢甲,“玉大人僵刮,你說我怎么就攤上這事○信#” “怎么了搞糕?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)曼追。 經(jīng)常有香客問我窍仰,道長(zhǎng),這世上最難降的妖魔是什么礼殊? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任驹吮,我火速辦了婚禮,結(jié)果婚禮上晶伦,老公的妹妹穿的比我還像新娘碟狞。我一直安慰自己,他們只是感情好婚陪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布族沃。 她就那樣靜靜地躺著,像睡著了一般泌参。 火紅的嫁衣襯著肌膚如雪脆淹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天盖溺,我揣著相機(jī)與錄音,去河邊找鬼铣缠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛攘残,可吹牛的內(nèi)容都是我干的为狸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辐棒,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼牍蜂!你這毒婦竟也來了泰涂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤逼蒙,失蹤者是張志新(化名)和其女友劉穎从绘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體是牢,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡僵井,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驳棱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片批什。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖社搅,靈堂內(nèi)的尸體忽然破棺而出驻债,到底是詐尸還是另有隱情,我是刑警寧澤形葬,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布合呐,位于F島的核電站,受9級(jí)特大地震影響笙以,放射性物質(zhì)發(fā)生泄漏合砂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一源织、第九天 我趴在偏房一處隱蔽的房頂上張望翩伪。 院中可真熱鬧,春花似錦谈息、人聲如沸缘屹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轻姿。三九已至,卻和暖如春逻炊,著一層夾襖步出監(jiān)牢的瞬間互亮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工余素, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豹休,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓桨吊,卻偏偏與公主長(zhǎng)得像威根,于是被迫代替她去往敵國(guó)和親凤巨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • android中Retrofit源碼解析(新版) 在android開發(fā)中我們?cè)鷳?yīng)用發(fā)起網(wǎng)絡(luò)請(qǐng)求的時(shí)候洛搀,不免需要使...
    CharlesCT閱讀 2,054評(píng)論 0 6
  • 本文基于Retrofit2的2.4.0版本 網(wǎng)絡(luò)調(diào)用流程分析 我們?cè)诎l(fā)起異步網(wǎng)絡(luò)請(qǐng)求時(shí)是這樣調(diào)用的: 總結(jié)起來就是...
    小小的coder閱讀 225評(píng)論 0 0
  • 一.Retrofit是什么 Retrofit是square開源的一個(gè)Restful的http網(wǎng)絡(luò)請(qǐng)求框架的封裝彰檬。網(wǎng)...
    雷濤賽文閱讀 1,030評(píng)論 1 4
  • 原文鏈接 http://www.qinglinyi.com/posts/retrofit/ 本文是關(guān)于Retrof...
    卓碼閱讀 979評(píng)論 0 1
  • Retrofit2是針對(duì)于Android/Java的僧叉、基于okHttp的瓶堕、一種輕量級(jí)且安全的郎笆、并使用注解方式的網(wǎng)絡(luò)...
    PeOS閱讀 390評(píng)論 1 1