Retrofit 原理解析

Retrofit 是什麼?

 * Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to
 * define how requests are made. Create instances using {@linkplain Builder
 * the builder} and pass your interface to {@link #create} to generate an implementation.

Retrofit 是一個對於OkHttp 的增強附件,可以直接通過註解的方式,寫網絡請求方式(GET,POST),並且具備把返回結果轉換成Java對象的擴展能力。

常見寫法:

public interface TestService {

    @GET("api/weather/city/101030100/")
    Call<WeatherData> getWeather2();
    public class WeatherData{
        public String message;
        public String date;
    }

    @GET("api/weather/city/101030100/")
    Observable<WeatherData> getWeather4();
}

實現原理

1.首先利用Java動態代理技術,根據接口生成一個代理類。
retrofit2.Retrofit#create

  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 {
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

2. 每次調用該代理對象的方法的時候,就會走到 invoke方法裏。我們會在這個方法裏解析註解,拿到請求參數,比如請求方法,參數等信息。
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
retrofit2.ServiceMethod#parseAnnotations

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

3.執行到loadServiceMethod(method).invoke(args != null ? args : emptyArgs);方法的地方:
retrofit2.HttpServiceMethod#invoke

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

4.然後在OkHttpCall裏面,發起真正的網絡請求
retrofit2.OkHttpCall#enqueue

  @Override public void enqueue(final Callback<T> callback) {
    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) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }
    });
  }

5.將網絡返回的數據,根據Convert 轉換成對應的接口返回的泛型類型。

如Call <WeatherData>,會把返回結果轉成WeatherData 對象。

retrofit2.OkHttpCall#parseResponse

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

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

    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
  
    }
  }

6.根據接口返回的實參類型,找到對應的實參轉換工廠,生成返回值。
如果返回時Call<WeatherData> 則返回Call對象,如Observable<WeatherData> 則返回Observable對象。

如果是Call對象,則對應的Adapter 是:
retrofit2.DefaultCallAdapterFactory#get

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

                public Call<Object> adapt(Call<Object> call) {
                    return (Call)(executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));
                }
            };

如果返回是Observable,那麼是:
hu.akarnokd.rxjava3.retrofit.RxJava3CallAdapter#adapt

  @Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

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

最終RxJava將結果返回給調用的地方。

    @Override public void onNext(Response<R> response) {
      if (response.isSuccessful()) {
        observer.onNext(response.body());
      }
    }

反射獲取返回類型:

method.getGenericReturnType()

這個方法是返回的一個全類型,比如對於 Observable<WeatherData> getWeather4(); 返回值是下面截圖中的類型:

在這裏插入圖片描述

我們可以根據返回的總類型,拿到返回的泛型類型:

  ParameterizedType type
    Type[] types = type.getActualTypeArguments();

比如對於 Observable<WeatherData> getWeather4(); 我們可以先根據method.getGenericReturnType() 拿到整個的返回類型,然後調用 getActualTypeArguments 方法拿到泛型類型WeatherData

在這裏插入圖片描述

總結:

單一職責:

如果我需要一個功能,那麼暴露接口出去,讓別人實現,這就具備了可拓展性。比如說結果轉換,返回結果的工廠。Retrofit只負責整個框架各個部門工作起來。

結果轉換
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);

CallAdapted 負責返回類型的轉換

反射和註解

retrofit2.OkHttpCall 是真正的調用okhttp 的地方。
retrofit2.RequestFactory#create 負責生成請求的參數

Q:爲什麼要這樣寫:
  public <T> T create(final Class<T> service) { 
  而不是
    public <T> T create(final Class service) {
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章