Retrofit源碼學(xué)習(xí)

基本用法

 Retrofit retrofit =new Retrofit.Builder().client(okhttpClient).baseUrl("http://localhost/").addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(GsonConverterFactory.create()).build();
 API api=retrofit.create(API.class);
        

上面代碼主要?jiǎng)?chuàng)建了Retrofit對(duì)象斤寇,并且為Retrofit對(duì)象分別設(shè)置了OkhttpClient對(duì)象捞蚂、baseUrl福荸、CallAdapterFactory對(duì)象和ConvertFactory對(duì)象腊瑟。最關(guān)鍵的是create方法

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

以上是create方法的全部代碼喂分,只有幾十行锦庸,看著也不是特別復(fù)雜。第一行 Utils.validateServiceInterface(service);從名字就可以知道是用來檢驗(yàn)參數(shù)service是否是一個(gè)接口的蒲祈,不是重點(diǎn)甘萧,不需要重點(diǎn)關(guān)注。第二行validateEagerly默認(rèn)是false,所以第三行不會(huì)執(zhí)行讳嘱,(注:如果我們?cè)跇?gòu)建Retrofit對(duì)象時(shí)設(shè)置了validateEagerly屬性為true,那么第三行eagerlyValidateMethods(service)會(huì)執(zhí)行,這個(gè)方法中會(huì)遍歷接口中所有的方法酿愧,如果不是default方法沥潭,就調(diào)用loadServiceMethod方法,將接口中的所有方法緩存嬉挡,default方法是jdk1.8當(dāng)中引入的钝鸽,在jdk1.8當(dāng)中接口可以有實(shí)現(xiàn)方法,只要在方法前加default關(guān)鍵字)庞钢。在create方法的第五行就直接返回了一個(gè)動(dòng)態(tài)代理對(duì)象拔恰,也就是說create方法實(shí)際就做了兩件事,第一基括、驗(yàn)證參數(shù)是不是接口類型颜懊,第二、返回代理對(duì)象。那么重點(diǎn)關(guān)注的代碼都在代理對(duì)象里面了河爹。Proxy.newProxyInstance方法返回一個(gè)實(shí)現(xiàn)了參數(shù)service接口的對(duì)象匠璧,也就是開頭 API api=retrofit.create(API.class)中的api對(duì)象。根據(jù)動(dòng)態(tài)代理的特性咸这,我們每次調(diào)用api這個(gè)對(duì)象的方法夷恍,其實(shí)調(diào)用的是InvocationHandler當(dāng)中的invoke方法,也就是create方法當(dāng)中第七行的new InvocationHandler()對(duì)象中的invoke方法媳维。在invoke方法當(dāng)中首先驗(yàn)證了方法是否是Object的方法酿雪,如果是,就直接調(diào)用并返回了侄刽。然后判斷方法是否是默認(rèn)方法指黎,如果是,也直接返回了唠梨。那么重點(diǎn)就在最后四行代碼當(dāng)中了袋励。

loadServiceMehod方法分析

在create方法的倒數(shù)第四行調(diào)用了Retrofit的loadServiceMethod方法,該方法傳入method參數(shù)返回了一個(gè)ServiceMethod對(duì)象当叭。下面是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 = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

這個(gè)方法也很簡(jiǎn)單茬故,首先判斷緩存當(dāng)中有沒有method對(duì)應(yīng)的ServiceMethod對(duì)象,如果有就返回該對(duì)象蚁鳖,沒有就創(chuàng)建對(duì)象并將其放入緩存磺芭。在構(gòu)建ServiceMethod對(duì)象時(shí)傳入了retrofit對(duì)象和method對(duì)象。

創(chuàng)建OkHttpCall對(duì)象

 OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

OkHttpCall對(duì)象的構(gòu)造方法很簡(jiǎn)單醉箕,僅僅是對(duì)兩個(gè)屬性賦值而已钾腺。到目前為止還沒有看到一行關(guān)于網(wǎng)絡(luò)請(qǐng)求的代碼,那么網(wǎng)絡(luò)請(qǐng)求的代碼應(yīng)該是在create方法最后一行當(dāng)中了讥裤。

CallAdapter的adapt方法

在Retrofit的create方法最后一行調(diào)用了ServiceMethod的callAdapter的adapt方法放棒。ServiceMethod的CallAdapter對(duì)象是通過Retrofit中設(shè)置的CallAdapterFactoty對(duì)象創(chuàng)建出來的,我設(shè)置的是RxJava2CallAdapterFactory己英,那主要的網(wǎng)絡(luò)請(qǐng)求邏輯應(yīng)該是在RxJava2CallAdapterFactory里面了间螟。

RxJava2CallAdapterFactory的get方法

@Override
  public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);

    if (rawType == Completable.class) {
      // Completable is not parameterized (which is what the rest of this method deals with) so it
      // can only be created with a single configuration.
      return new RxJava2CallAdapter(Void.class, scheduler, false, true, false, false, false, true);
    }

    boolean isFlowable = rawType == Flowable.class;
    boolean isSingle = rawType == Single.class;
    boolean isMaybe = rawType == Maybe.class;
    if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
      return null;
    }

    boolean isResult = false;
    boolean isBody = false;
    Type responseType;
    if (!(returnType instanceof ParameterizedType)) {
      String name = isFlowable ? "Flowable" : isSingle ? "Single" : "Observable";
      throw new IllegalStateException(name + " return type must be parameterized"
          + " as " + name + "<Foo> or " + name + "<? extends Foo>");
    }

    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
    Class<?> rawObservableType = getRawType(observableType);
    if (rawObservableType == Response.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Response must be parameterized"
            + " as Response<Foo> or Response<? extends Foo>");
      }
      responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
    } else if (rawObservableType == Result.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Result must be parameterized"
            + " as Result<Foo> or Result<? extends Foo>");
      }
      responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
      isResult = true;
    } else {
      responseType = observableType;
      isBody = true;
    }

    return new RxJava2CallAdapter(responseType, scheduler, isResult, isBody, isFlowable,
        isSingle, isMaybe, false);
  }

該方法返回一個(gè)CallAdapter對(duì)象,也就是ServiceMethod中的CallAdapter對(duì)象损肛。首先分析一下該對(duì)象的創(chuàng)建過程厢破。該方法首先判斷我們調(diào)用的接口方法的返回值類型,返回值類型必須是Completable治拿,Observable摩泪,F(xiàn)lowable,Single劫谅,Maybe中的一種见坑,否則會(huì)返回null嚷掠。判斷完返回類型接著判斷返回類型的泛型,最后返回一個(gè)RxJava2CallAdapter對(duì)象鳄梅。

RxJava2CallAdapter的adapt方法

@Override public <R> Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = new CallObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }

這個(gè)方法主要根據(jù)接口方法返回值的類型和泛型類型返回不同的Observable叠国,如果返回值泛型是Result類型,返回ResultObservable戴尸,如果是返回值泛型是Response類型粟焊,返回responseObservable,如果是自定義的類型則返回BodyObservable孙蒙。到目前為止還是沒有發(fā)現(xiàn)網(wǎng)絡(luò)請(qǐng)求相關(guān)的代碼项棠,那么網(wǎng)絡(luò)請(qǐng)求的代碼應(yīng)該是在Observable里面了。平時(shí)請(qǐng)求一般都是自定義類型挎峦,那么主要看一下Observable當(dāng)中的邏輯香追。

CallObservable

final class CallObservable<T> extends Observable<Response<T>> {
  private final Call<T> originalCall;

  CallObservable(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    observer.onSubscribe(new CallDisposable(call));

    boolean terminated = false;
    try {
      Response<T> response = call.execute();
      if (!call.isCanceled()) {
        observer.onNext(response);
      }
      if (!call.isCanceled()) {
        terminated = true;
        observer.onComplete();
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (terminated) {
        RxJavaPlugins.onError(t);
      } else if (!call.isCanceled()) {
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }
  }

  private static final class CallDisposable implements Disposable {
    private final Call<?> call;

    CallDisposable(Call<?> call) {
      this.call = call;
    }

    @Override public void dispose() {
      call.cancel();
    }

    @Override public boolean isDisposed() {
      return call.isCanceled();
    }
  }
}

CallObservable中有一個(gè)Call對(duì)象的引用,這個(gè)對(duì)象就是在Retrofit的create方法當(dāng)中的 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args)這個(gè)okHttpCall對(duì)象坦胶。在CallObservable的subscribeActual方法當(dāng)中執(zhí)行了call.execute()透典,這行代碼返回了一個(gè)Response(注:這個(gè)Response類是Retrofit包當(dāng)中的,并非OkHttp當(dāng)中的)對(duì)象顿苇,那網(wǎng)絡(luò)請(qǐng)求的代碼應(yīng)該是在這個(gè)方法中執(zhí)行峭咒。

OkHttpCall的execute方法

@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else {
          throw (RuntimeException) creationFailure;
        }
      }

      call = rawCall;
      if (call == null) {
        try {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          creationFailure = e;
          throw e;
        }
      }
    }

    if (canceled) {
      call.cancel();
    }

    return parseResponse(call.execute());
  }

這個(gè)方法的邏輯很簡(jiǎn)單,首先創(chuàng)建一個(gè)okhttp3.Call對(duì)象纪岁,然后執(zhí)行call.execute方法凑队,最后將okhttp當(dāng)中的Response類型轉(zhuǎn)換為Retrofit當(dāng)中的Response對(duì)象。

OkHttpCall的parseResponse方法

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

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = serviceMethod.toResponse(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;
    }
  }

這個(gè)方法的主要邏輯就是根據(jù)不同的http響應(yīng)碼返回不同的Retrofit.Response幔翰。如果是正常的200響應(yīng)碼漩氨,會(huì)走最后這個(gè)return語(yǔ)句。返回一個(gè)Retrofit.Response對(duì)象,該對(duì)象封裝了一個(gè)泛型類型的body和一個(gè)OkHttp.Response對(duì)象遗增,這個(gè)泛型對(duì)象時(shí)通過ServiceMethod的toResponse方法返回的叫惊,在toResponse方法當(dāng)中會(huì)調(diào)用Converter的convert方法,也就是在創(chuàng)建Retrofit的時(shí)候設(shè)置的ConvertFactory創(chuàng)建出來的Convert做修,通常是設(shè)置GsonConvert,也就是將網(wǎng)絡(luò)請(qǐng)求的響應(yīng)體解析成接口方法泛型里面的類型霍狰。

BodyObservable

final class BodyObservable<T> extends Observable<T> {
  private final Observable<Response<T>> upstream;

  BodyObservable(Observable<Response<T>> upstream) {
    this.upstream = upstream;
  }

  @Override protected void subscribeActual(Observer<? super T> observer) {
    upstream.subscribe(new BodyObserver<>(observer));
  }

  private static class BodyObserver<R> implements Observer<Response<R>> {
    private final Observer<? super R> observer;
    private boolean terminated;

    BodyObserver(Observer<? super R> observer) {
      this.observer = observer;
    }

    @Override public void onSubscribe(Disposable disposable) {
      observer.onSubscribe(disposable);
    }

    @Override public void onNext(Response<R> response) {
      if (response.isSuccessful()) {
        observer.onNext(response.body());
      } else {
        terminated = true;
        Throwable t = new HttpException(response);
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }

    @Override public void onComplete() {
      if (!terminated) {
        observer.onComplete();
      }
    }

    @Override public void onError(Throwable throwable) {
      if (!terminated) {
        observer.onError(throwable);
      } else {
        // This should never happen! onNext handles and forwards errors automatically.
        Throwable broken = new AssertionError(
            "This should never happen! Report as a bug with the full stacktrace.");
        //noinspection UnnecessaryInitCause Two-arg AssertionError constructor is 1.7+ only.
        broken.initCause(throwable);
        RxJavaPlugins.onError(broken);
      }
    }
  }
}

前面這些網(wǎng)絡(luò)請(qǐng)求,響應(yīng)解析功能都是在CallObservable當(dāng)中完成的缓待,但最終返回給我們用的卻是BodyObservable蚓耽,BodyObservable對(duì)CallObservable做了一次封裝渠牲,onNext只傳了Retrofit.Response的body對(duì)象旋炒,也就時(shí)Gson解析出來的對(duì)象。這樣就只能得到響應(yīng)體签杈,某些時(shí)候需要用到響應(yīng)頭瘫镇,可以將接口方法的返回值的泛型使用Retrofit.Response就可以了鼎兽。

總結(jié)

1.創(chuàng)建Retrofit對(duì)象。
2.調(diào)用Retrofit對(duì)象的create方法返回動(dòng)態(tài)代理對(duì)象铣除。
3.調(diào)用動(dòng)態(tài)代理對(duì)象的方法谚咬。
4.調(diào)用CallAdapter的adapt方法,返回一個(gè)Observable對(duì)象尚粘。
5.在Observable對(duì)象subscribe方法當(dāng)中進(jìn)行網(wǎng)絡(luò)請(qǐng)求和響應(yīng)體的解析择卦。
(注:省略了根據(jù)接口方法注解生成Request部分)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市郎嫁,隨后出現(xiàn)的幾起案子秉继,更是在濱河造成了極大的恐慌,老刑警劉巖泽铛,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尚辑,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盔腔,警方通過查閱死者的電腦和手機(jī)杠茬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弛随,“玉大人瓢喉,你說我怎么就攤上這事∧煊模” “怎么了灯荧?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)盐杂。 經(jīng)常有香客問我逗载,道長(zhǎng),這世上最難降的妖魔是什么链烈? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任厉斟,我火速辦了婚禮,結(jié)果婚禮上强衡,老公的妹妹穿的比我還像新娘擦秽。我一直安慰自己,他們只是感情好漩勤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布感挥。 她就那樣靜靜地躺著,像睡著了一般越败。 火紅的嫁衣襯著肌膚如雪触幼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天究飞,我揣著相機(jī)與錄音置谦,去河邊找鬼堂鲤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛媒峡,可吹牛的內(nèi)容都是我干的瘟栖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谅阿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼半哟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起签餐,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镜沽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后贱田,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缅茉,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年男摧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔬墩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耗拓,死狀恐怖拇颅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乔询,我是刑警寧澤樟插,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站竿刁,受9級(jí)特大地震影響黄锤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜食拜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一鸵熟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧负甸,春花似錦流强、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蚕捉,卻和暖如春奏篙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鱼冀。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工报破, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人千绪。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓充易,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親荸型。 傳聞我的和親對(duì)象是個(gè)殘疾皇子盹靴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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