Retrofit2.5如何發送請求和處理響應?

Retrofit對請求方法的解析

Retrofit對我們在接口類中定義的方法是如何轉換成了請求,又如何處理響應。這一切都在它的loadServiceMethod方法中

代碼基于Retrofit2.5.0

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

主要是調用ServiceMethod.parseAnnotations

  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);//這里就是對請求的解析,也就是我們定義的接口方法

    Type returnType = method.getGenericReturnType();//獲取返回的類型
    //省略無關代碼

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

RequestFactory.parseAnnotations這個方法就是對我們定義的接口方法的解析,在里面解析注解和使用反射得到了關于請求的所有信息。

響應的處理

在完成了對請求的處理后構建了RequestFactory類,這個類里面包含了請求的所有信息:

final class RequestFactory {
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

  private final Method method;
  private final HttpUrl baseUrl;
  final String httpMethod;
  private final @Nullable String relativeUrl;
  private final @Nullable Headers headers;
  private final @Nullable MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;

接下來繼續來看ServiceMethod的parseAnnotations剩下的語句

ServiceMethod.parseAnnotations

  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //省略無關代碼

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);//對響應的處理
  }

HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);//創建請求適配器
    Type responseType = callAdapter.responseType();
    //省略無關代碼
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);//創建響應數據轉換器(Gson)

    okhttp3.Call.Factory callFactory = retrofit.callFactory;//Okhttp請求客戶端
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
  }

創建請求適配器CallAdapter

首先進入第一行
HttpServiceMethod.createCallAdapter

  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();//獲取返回的類型
    Annotation[] annotations = method.getAnnotations();//獲取注解
    try {
      //noinspection unchecked
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
  }

在獲取了方法的返回類型和注解之后,調用

retrofit.callAdapter

  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }
  
    public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
      //空判斷
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

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

這里面是一個循環獲取請求適配器工廠數組callAdapterFactories,在retrofit創建的時候,我們可以知道往這個數組里面加的是Android平臺默認的ExecutorCallAdapterFactory

public Retrofit build() {
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));   
}
static class Android extends Platform {
    @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      //這里可以看到返回的類
      ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }    
}

在剛才的循環里,調用了它的get方法,實際就是調用

ExecutorCallAdapterFactory.get

  @Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);//根據返回類型獲取泛型里面的想要獲取的響應類型
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

我們定義的返回類型一般是泛型的形式,如Call<Response>或者Observable<Response>,所以Utils.getCallResponseType就是取出泛型里面的類型。最后將得到的類型傳入新建的CallAdapter

    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };

自此就完成了CallAdapter的創建,這里記住它的adapt方法,里面是返回的ExecutorCallbackCall,這個后面會調用,再來繼續看。

HttpServiceMethod的parseAnnotations第一行代碼到此就完了,繼續往下執行:

創建響應數據轉換器(如Gson)和請求客戶端

HttpServiceMethod.parseAnnotations

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();//獲取具體的響應類型
    //省略無關代碼
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
  }

注意這里傳給responseConverter的responseType是我們剛才獲取Call泛型里面的具體類型,也就是我們想要拿到的實體類類型。

這個過程跟剛才創建CallAdapter的過程很像,就連方法名都很像,所以來看看createResponseConverter方法:

HttpServiceMethod.createResponseConverter

  private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    try {
      return retrofit.responseBodyConverter(responseType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create converter for %s", responseType);
    }
  }

通過method的getAnnotations拿到注解列表,然后跟返回類型傳入responseBodyConverter方法:

retrofit.responseBodyConverter

  public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }
  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }

這個過程簡直跟剛才創建CallAdapter的過程一模一樣,也是循環從converterFactories取出Converter,根據之前Retrofit的創建時我們傳入的是GsonConverterFactory,所以是調用的它的responseBodyConverter方法:

GsonConverterFactory.responseBodyConverter

  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

這里的代碼就很面熟了,通過TypeToken獲取類型,之后返回一個Gson解析器,它的convert就是調用Gson進行泛型的解析。

GsonResponseBodyConverter

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      T result = adapter.read(jsonReader);
      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
        throw new JsonIOException("JSON document was not fully consumed.");
      }
      return result;
    } finally {
      value.close();
    }
  }
}

到這里就完成了響應字符串的解析器的創建,接下來會執行

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);

創建okhttp請求的客戶端,這里命名為callFactory,在Retrofit創建的時候我們傳入的okhttpClient就是賦值給了callFactory,最后將創建好的對象傳入HttpServiceMethod返回。

到此為止就執行完了HttpServiceMethod的parseAnnotations方法,在這個方法里面,創建了幾個重要的東西

  • 對請求和響應做具體處理的CallAdapter類,具體為ExecutorCallAdapterFactory,這里要注意它的adapt方法返回ExecutorCallbackCall
  • 響應數據解析工廠Converter,具體為GsonResponseBodyConverter
  • okhttp請求客戶端

發送請求

終于到了這一步了,在做好了所有的準備工作之后,最終Retrofit怎么來發送請求呢,首先一步步回到最開始的地方:
在HttpServiceMethod.parseAnnotations方法是在ServiceMethod的parseAnnotations調用的

ServiceMethod.parseAnnotations

abstract class ServiceMethod<T> {
  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);
  }

  abstract T invoke(Object[] args);
}

然后ServiceMethod.parseAnnotations方法是在Retrofit的loadServiceMethod調用的

然后loadServiceMethod是在Retrofit的create方法里面創建動態代理的invoke調用的

Retrofit.create

  public <T> T create(final Class<T> service) {
    //省略無關代碼
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          //省略無關代碼

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            //省略無關代碼
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

可以看到,在loadServiceMethod之后調用了invoke方法,也就是ServiceMethod的invoke方法,點進去之后發現它是個ServiceMethod是個抽象類,它的invoke需要實現類來重寫:

abstract class ServiceMethod<T> {
    abstract T invoke(Object[] args);
}

ServiceMethod類只有一個實現類,也就是我們剛才看到過的HttpServiceMethod,所以實際上調用的是它的invoke方法:

HttpServiceMethod.invoke

  @Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }

在這里只有一行代碼,實際上是調用callAdapter.adapt,那這個callAdapter是什么呢?剛才我們已經知道它是ExecutorCallAdapterFactory創建的,然后在創建的callAdapter的adapt方法返回ExecutorCallbackCall類,所以來看看這個類:

ExecutorCallbackCall是ExecutorCallAdapterFactory的靜態內部類

ExecutorCallbackCall

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

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

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

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

    @Override public boolean isExecuted() {
      return delegate.isExecuted();
    }

    @Override public Response<T> execute() throws IOException {
      return delegate.execute();
    }

    @Override public void cancel() {
      delegate.cancel();
    }

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

    @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
    @Override public Call<T> clone() {
      return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
    }

    @Override public Request request() {
      return delegate.request();
    }
  }

在這個類里面,我們就看到了很多很熟悉的方法,enqueue方法發送請求,實際的請求和處理就是在這里面,但是還有疑惑就是具體的處理我們還是沒看到,callbackExecutordelegate這兩個熟悉才是關鍵所在:

callbackExecutor

這個是在ExecutorCallAdapterFactory的構造方法中傳入的,它的構造方法又是在Platform的defaultCallAdapterFactories方法中調用的,看到Platform,自然可以想到它的Android平臺類,所以這個callbackExecutor實際上是MainThreadExecutor

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

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

其實代碼很簡單,使用了我們最常用的Handler,讓代碼在主線程中執行,也就是我們通常做的在子線程請求網絡,主線程中更新UI。

delegate

delegate實際是在HttpServiceMethod的invoke方法里傳入:

  @Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }

實際上是OkHttpCall這個類,這個類里面就是發送請求和處理響應的具體處理,代碼很多,我們只看看構造方法和enqueue

  OkHttpCall(RequestFactory requestFactory, Object[] args,
      okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) {
    this.requestFactory = requestFactory;//請求工廠,里面包含了請求的所有信息
    this.args = args;//參數
    this.callFactory = callFactory;//請求客戶端,okhttp
    this.responseConverter = responseConverter;//響應的json解析器(Gson)
  }

OkHttpCall.enqueue

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

    okhttp3.Call call;
    Throwable failure;

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

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

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

    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

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

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

代碼其實很簡單,就是使用okhttp請求,然后在響應方法onResponse做相應的解析和處理,最后完成網絡請求。

總結

Retrofit對響應的解析大概可分為

  1. 創建處理適配器CallAdapter,具體實現類為ExecutorCallbackCall,在這里面進行發送請求和處理響應等相關的操作,最終是調用okhttp進行網絡請求
  2. 創建響應數據轉換器Converter,具體實現類為GsonResponseBodyConverter,用于對返回json數據的解析,這個是我們自己傳入的Gson解析工廠,Retrofit也支持其他的第三方解析庫
  3. 發送請求,具體的操作類是OkHttpCall來發送請求和處理響應,MainThreadExecutor來做回調的處理,在主線程中處理已經轉化好的實體類。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容

  • Retrofit2 源碼解析 注意: 本文是對源碼的一個跟蹤,會對每一行代碼有具體的闡述,但是不會介紹 Retro...
    Yjnull閱讀 2,959評論 3 17
  • 適配器模式上一篇文章我們已經分析了Retrofit解析注解封裝進ServiceMethod的流程,讀者在這里要記住...
    andcoder閱讀 669評論 0 2
  • 一,前言 Retrofit其實是將OKhttp封裝起來,和volley一樣。那解析Retrofit其實就是解析它如...
    求閑居士閱讀 1,342評論 2 5
  • 女兒最近臉上有白色的斑點,昨天帶她去醫院檢查。因為知道如果一開始就告訴她我們去醫院,她肯定會排斥和不愿意。一開...
    薔薇的夏天閱讀 187評論 0 0