秒懂Retrofit2之CallAdapter

【版權申明】非商業目的註明出處可自由轉載
博文地址:
出自:shusheng007

系列文章
秒懂的Retrofit2源碼詳解
用Retrofit+RxJava2封裝優雅的網絡請求框架
秒懂Retrofit2之Converter
秒懂Retrofit2之GsonConverter

概述

Retrofit2 已經成爲Android開發網絡請求當之無愧的扛把子了,我們很有必要對自己經常使用的東西有個深入的瞭解。

Retrofit2 中有兩個非常精彩的設計:ConverterCallAdapter, 通過這兩個接口,Retrofit的可擴展性被極大的增強了,用戶可以根據需求自由擴展。在上一篇文章 秒懂Retrofit2之Converter中我們對Converter做了比較詳細的解析,這篇文章就對Calladapter做一個比較深入的瞭解。

作用

Retrofit2 中有兩個非常精彩的設計:ConverterCallAdapter, 這是兩個接口,通過這兩個接口,retrofit的可擴展性被極大的增強了,用戶可以根據需求自由擴展。

假如有如下代碼:其中UserPerson 是兩個自定義類

    @POST
    Observable<List<User>>m1(@Body Person rBody);
    
    @POST
    Call<List<User>>m2(@Body Person rBody);

仔細觀察方法m1和m2發現他們的返回類型有一定的區別,m1 的放回類型是Rxjava2 的 Observable<T> 而m2是Retrofit2 的Call<T>。這個類型就是由CallAdapter 決定的,例如Call<T> 類型就是通過CallAdapter將得到的。Retrofit2 的方法的返回值必須是泛型類型,例如Call<T>,通過調用CallAdapter裏的 adapt()方法,將方法的返回值適配爲類似Call<T>的樣子,而在這個過程中又調用了ConverterresponseBodyConverter()方法,將htpp返回的ResponseBody類型的數據轉換爲Call<T>裏面的 T

源碼解析

我們先看一下CallAdapter的源碼:

public interface CallAdapter<R, T> {
  //retrofit 方法的返回類型的泛型參數代表的類型,例如 方法的返回類型(returnType)爲Call<User> ,那麼responseType  爲User
  Type responseType();
  //Returns an instance of {@code T} which delegates to {@code call}.
  T adapt(Call<R> call);

  abstract class Factory {
    //獲得一個call adapter
    //returnType 爲接口中方法的泛型返回類型例如 Call<User>
    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);

   //兩個工具方法
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

接口很簡單,裏面僅有兩個方法,responseType()adapt().
responseType() 是一個取值方法,使用它獲得當前方法的響應類型。主要用途是檢查我們定義的方法返回值裏面那個泛型參數的類型是否正確,例如Call<User>是正確的,而Call<okhttp3.Response> 則是不正確的。
adapt() 負責適配

接口裏面還有一個內部類Factory,我們就是通過這個factory裏的get方法獲得相應的Adapter的

使用機制

那麼CallAdapter 在retrofit2中是如何發揮作用的呢,關鍵代碼在HttpServiceMethod<ResponseT, ReturnT> 類中的invoke()方法中,程序每發起一個HTTP請求時,首先就會調用這個方法:

  //提交一個http請求,返回我們設定的類型的結果,例如Call<User>
  @Override ReturnT invoke(@Nullable Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<ResponseT>(requestFactory, args, callFactory, responseConverter));
  }

Retrofit2的方法之所以可以返回Call<T>是因爲其有兩個默認的CallAdapter實現,DefaultCallAdapterFactoryExecutorCallAdapterFactory, Retrofit2 會自動判斷當前運行的平臺,如果發現是Android平臺則使用ExecutorCallAdapterFactory,其他情況使用另一個。

DefaultCallAdapterFactory

DefaultCallAdapterFactory 源碼如下:

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

  @Override
  public 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 call;
      }
    };
  }
}

代碼很簡單,通過get獲得一個CallAdapter。首先要求方法的返回值returnType的原始類型必須是Call類型,就是說returnType必須爲Call<T>,然後返回一個Call<Object>數據。
這就決定了你聲明方法時候必須是如下的形式:

@POST
Call<List<User>>m2(@Body Person rBody);

返回值類型必須是Call<Object>的形式,你說你想返回Rxjava2的Observerable,別鬧,這個CallAdapter不認識這個東東。

ExecutorCallAdapterFactory

其實ExecutorCallAdapterFactory 應該是做Android開發的重點關注的,其與DefaultCallAdapterFactory 是一脈相承的,唯一的增強就是通過一個MainThreadExecutor 將結果回調切換到了UI線程上,讓我們可以直接在結果回調中操作UI控件。

以下是MainThreadExecutor的源碼,是不是有一種熟悉的味道

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }

ExecutorCallAdapterFactory 的源碼如下:

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
       this.callbackExecutor = callbackExecutor;
  }

  @Override
  public 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);
      }
    };
  }

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

  }
}

從上面的源碼中可以看到DefaultCallAdapterFactoryExecutorCallAdapterFactory唯一的區別就是在adapt()方法中返回的那個Call接口的實現類實例不一樣。

 //DefaultCallAdapterFactory 裏的實現方式
  @Override public Call<Object> adapt(Call<Object> call) {
     return call;
  }

  //ExecutorCallAdapterFactory 裏的實現方式
  @Override public Call<Object> adapt(Call<Object> call) {
     return new ExecutorCallbackCall<>(callbackExecutor, call);
  }

我們就是在ExecutorCallbackCall 裏面將結果回調切換到了UI線程。

理解了原理後,自定義一個CallAdapter就變的很容易了。 我們使用比較多的就是與Rxjava2結合的RxJava2CallAdapterFactory, 這個自定義的CallAdapter算是比較複雜的了,那是因爲Rxjava2比較難於上手,其實實現原理還是那一套。就是不返回Call<T>, 轉而返回Rxjava2自己的類,例如Onserverable<T>.

總結

可見一個設計優良的類庫,會給用戶很大的擴展空間,這一點我們應該多加學習。

最後,求關注,求點贊!有任何疑問可以評論留言,我會盡力回覆的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章