retrofit原理詳解

前言

  Retrofit retrofit = new Retrofit.Builder()
                              .baseUrl("http://www.reibang.com/")
                              //設(shè)置轉(zhuǎn)換工廠
                              .addConverterFactory(GsonConverterFactory.create())
                              //設(shè)置適配器
                              .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                              .build();

這里之所以叫Retrofit客戶端。客戶端提供的子系統(tǒng)有:
1.serviceMethodCache(自定義的接口映射對象集合)
2.baseUrl(請求地址)
3.callFactory(默認(rèn)為OkHttpCall)
4.converterFactories(數(shù)據(jù)解析器工廠集合)
5.callAdapterFactories(Call適配器工廠集合)
6.callbackExecutor(回調(diào)執(zhí)行钱豁,android平臺默認(rèn)為MainThreadExecutor)

關(guān)于Retrofit客戶端的創(chuàng)建

客戶端的創(chuàng)建有兩種方式:
第一種就是使用構(gòu)造函數(shù)棉钧,如下所示。
第二種就是Retrofit.Builder()挺益。
我們一般使用第二種方式來創(chuàng)建客戶端歉糜。

public final class Retrofit {
  //對網(wǎng)絡(luò)請求接口中方法注解進(jìn)行解析后得到的對象,緩存到map中
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
  //網(wǎng)絡(luò)請求器工廠
  final okhttp3.Call.Factory callFactory;
  //網(wǎng)絡(luò)請求適配器器工廠集合
  final List<CallAdapter.Factory> callAdapterFactories;
  //數(shù)據(jù)轉(zhuǎn)換器工廠集合
   final List<Converter.Factory> converterFactories;
  //回調(diào)方法執(zhí)行器
  final @Nullable Executor callbackExecutor;

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }
}

接下來看看通過構(gòu)建者模式創(chuàng)造的Retrofit客戶端望众,使用構(gòu)建者模式匪补,有如下好處伞辛,對外可以屏蔽創(chuàng)建對象的細(xì)節(jié),同時也可以自由配置Retrofit客戶端的屬性夯缺。

 public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;
  
  public Builder() {
      this(Platform.get());
    }
  

接著就到Platform.get()方法里

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        //安卓平臺的platform
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

接著看看這個安卓平臺的做了啥事

static class Android extends Platform {
    @IgnoreJRERequirement // Guarded by API check.
    @Override boolean isDefaultMethod(Method method) {
      if (Build.VERSION.SDK_INT < 24) {
        return false;
      }
      return method.isDefault();
    }

    @Override public Executor defaultCallbackExecutor() {
      //返回一個默認(rèn)的回調(diào)方法執(zhí)行器始锚,子線程請求后的數(shù)據(jù)通過這個來返回到主線程
      return new MainThreadExecutor();
    }
  
  //默認(rèn)的網(wǎng)絡(luò)請求適配器工廠是ExecutorCallAdapterFactory ,常用的還有
  //RxjavaCallAdapter喳逛,callAdapterFactory
    @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);
    }

    @Override int defaultCallAdapterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
    }
    
  //默認(rèn)的轉(zhuǎn)換器瞧捌,常用的有GsonConverterFactory
    @Override List<? extends Converter.Factory> defaultConverterFactories() {
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }

    @Override int defaultConverterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
    }

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

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

可以看出這個Build類初始化了如下:
Platform:安卓平臺對象 網(wǎng)絡(luò)請求適配器工廠:CallAdapterFactory
數(shù)據(jù)轉(zhuǎn)換器工廠:converterFactory 回調(diào)執(zhí)行器:callbackExecutor

初始化數(shù)據(jù)轉(zhuǎn)換器

addConverterFactory(GsonConverterFactory.creat())

先看看GsonConverterFactory.creat()里做了啥事

public final class GsonConverterFactory extends Converter.Factory {

     public static GsonConverterFactory create() {
    return create(new Gson());
  }

    public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }

    private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }
  
  //在自定義數(shù)據(jù)轉(zhuǎn)化器時需重寫這兩個方法
     @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

這就是創(chuàng)建了一個還有Gson對象的GsonConverterFactory,并添加進(jìn)converterFactorues中

 public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

由此看出
1.Retrofit默認(rèn)使用Gson進(jìn)行解析
2.若使用其他解析方式(如XML或Protocobuf)润文,也可通過自定義數(shù)據(jù)解析器來實現(xiàn)(必須繼承 Converter.Factory)姐呐,重寫那兩個方法。

還有最后一個步驟典蝌,build(),Retrofit客戶端就創(chuàng)建完成了曙砂。

 public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      
    //配置回調(diào)方法執(zhí)行器
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // 配置網(wǎng)絡(luò)請求適配器工廠
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // 配置數(shù)據(jù)轉(zhuǎn)換器工廠
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  }

創(chuàng)建網(wǎng)絡(luò)請求接口的實例

    public interface Service{
      @GET("wanandroid")
      Call<Bean> getCall();
}

  //使用了外觀模式,通過傳入class可以對每一個網(wǎng)絡(luò)請求接口的訪問
  Service service = retrofit.create(Service.class);

  Call<Bean> call = service.getCall();

Retrofit是通過動態(tài)代理模式創(chuàng)建網(wǎng)絡(luò)接口的實例骏掀,同時鸠澈,通過解析注解("wanandroid")進(jìn)行了網(wǎng)絡(luò)請求參數(shù)的配置

現(xiàn)在先來看接口的實例如何創(chuàng)建出來的

 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() {
          //這就是配置了那個數(shù)據(jù)轉(zhuǎn)換器和網(wǎng)絡(luò)適配器和回調(diào)池的platform
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public Object invoke(Object proxy, Method method, @Nullable 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);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

接著看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 = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

接著去看parseAnnotations里做了啥事

  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //這個就是去解析一些請求參數(shù)截驮,比如說是否有請求體笑陈,請求方法是get post等等
    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.");
    }
  //這里就是去解析注解信息帶參數(shù)path的
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

最后就生成了一個serviceMethod對象。

接下來去分析一下這個serviceMethod

final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
  //解析參數(shù)
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();
    if (responseType == Response.class || responseType == okhttp3.Response.class) {
      throw methodError(method, "'"
          + Utils.getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }

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

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

      //去遍歷網(wǎng)絡(luò)請求適配工廠
  // //網(wǎng)絡(luò)接口方法的返回值類型來確定合適的CallAdapter實例
  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);
    }
  }

  //去遍歷數(shù)據(jù)轉(zhuǎn)換器工廠
  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);
    }
  }

  private final RequestFactory requestFactory;
  private final okhttp3.Call.Factory callFactory;
  private final CallAdapter<ResponseT, ReturnT> callAdapter;
  private final Converter<ResponseBody, ResponseT> responseConverter;

  private HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
      CallAdapter<ResponseT, ReturnT> callAdapter,
      Converter<ResponseBody, ResponseT> responseConverter) {
    this.requestFactory = requestFactory;
    this.callFactory = callFactory;
    this.callAdapter = callAdapter;
    this.responseConverter = responseConverter;
  }
  
//重點在這葵袭,生成serviceMethod對象時涵妥,會調(diào)用到invoke方法
  @Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }
}

我們知道,Retrofit是對OkHttp做了一層封裝坡锡,具體的網(wǎng)絡(luò)發(fā)起人還是OkHttp蓬网,關(guān)鍵是怎么樣通過這個serviceMethod來完成的呢?
先來看看構(gòu)造函數(shù)鹉勒,接收四個帆锋,第一個就是請求工廠,包含所有的請求參數(shù)禽额,第二個就是網(wǎng)絡(luò)接口的參數(shù)锯厢,第三個就是網(wǎng)絡(luò)接口轉(zhuǎn)換工廠,第四個就是數(shù)據(jù)轉(zhuǎn)化工廠绵疲。

 OkHttpCall(RequestFactory requestFactory, Object[] args,
      okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) {
    this.requestFactory = requestFactory;
    this.args = args;
    this.callFactory = callFactory;
    this.responseConverter = responseConverter;
  }

這里已經(jīng)可以獲取到我們所有網(wǎng)絡(luò)請求發(fā)起需要的參數(shù)了哲鸳。
接著去看看adapt,這就是網(wǎng)絡(luò)接口請求返回類型的的適配,比如用的時RxjavaCallAdapter盔憨,返回的就是observerble徙菠。

網(wǎng)絡(luò)請求的發(fā)起

最后的請求由OkhttpCall來發(fā)起。

public void enqueue(final Callback<T> callback) {
 okhttp3.Call call;
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;
        }
}

這個callBack就是在創(chuàng)建時客戶端時那個ExtutorCallback郁岩。來完成線程的切換

總結(jié)

1.Retrofit將Http請求抽象成java接口
2.接口里用注解 描述和配置網(wǎng)絡(luò)請求參數(shù)
3.動態(tài)代理的方式來生成call對象婿奔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缺狠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子萍摊,更是在濱河造成了極大的恐慌挤茄,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冰木,死亡現(xiàn)場離奇詭異穷劈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)踊沸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門歇终,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人逼龟,你說我怎么就攤上這事评凝。” “怎么了腺律?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵奕短,是天一觀的道長。 經(jīng)常有香客問我匀钧,道長翎碑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任榴捡,我火速辦了婚禮杈女,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吊圾。我一直安慰自己,他們只是感情好翰蠢,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布项乒。 她就那樣靜靜地躺著,像睡著了一般梁沧。 火紅的嫁衣襯著肌膚如雪檀何。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天廷支,我揣著相機(jī)與錄音频鉴,去河邊找鬼。 笑死恋拍,一個胖子當(dāng)著我的面吹牛垛孔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播施敢,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼周荐,長吁一口氣:“原來是場噩夢啊……” “哼狭莱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起概作,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤腋妙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后讯榕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骤素,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年愚屁,在試婚紗的時候發(fā)現(xiàn)自己被綠了济竹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡集绰,死狀恐怖规辱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情栽燕,我是刑警寧澤罕袋,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站碍岔,受9級特大地震影響浴讯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔼啦,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一榆纽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捏肢,春花似錦奈籽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辩棒,卻和暖如春狼忱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背一睁。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工钻弄, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人者吁。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓窘俺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親砚偶。 傳聞我的和親對象是個殘疾皇子批销,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355