Retrofit2.0 源碼解析

首先介紹下Retrofit基本用法晚缩,先創(chuàng)建接口浅役,注解申明、請求方式Post/Get等

public interface Service {

    @POST("list")
    Call<User> loadRepo();

}

基本使用如下

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://www.reibang.com/u/c030e2bc8731")
                .build();

        Service service = retrofit.create(Service.class);
        Call<User> userCall = service.loadRepo();

        userCall.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {

            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {

            }
        });

上面是簡單的網(wǎng)絡(luò)請求流程瞻凤,那么我們來分析具體是怎么實(shí)現(xiàn)的憨攒,直接看源碼

Retrofit.Builder()方法

首先Retrofit.Builder()中Platform.get()最后調(diào)用findPlatform()得到平臺(tái)信息,可以看到支持Android阀参、Java8平臺(tái),其中還對Converter.Factory 設(shè)置默認(rèn)值肝集。

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
Retrofit.Builder().builder()方法
    public Retrofit build() {
      //baseUrl必須不為空
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //OkHttpClient對象
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //將回調(diào)傳遞,此時(shí)platform為Android 平臺(tái)蛛壳,在Retrofit.Builder()中初始化
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      //將callbackExecutor轉(zhuǎn)化成ExecutorCallAdapterFactory并添加到adapterFactories 集合中
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

1)以上可見baseUrl必須傳杏瞻,null則拋出異常。
2)若未傳入OkHttpClient則默認(rèn)創(chuàng)建一個(gè)衙荐,此處callFactory即OkHttpClient對象捞挥,OkHttpClient實(shí)現(xiàn)了okhttp3.Call.Factory接口。
3)callbackExecutor赫模,是用來將回調(diào)切換到主線程中去树肃,此處利用platform對象,對平臺(tái)進(jìn)行判斷瀑罗,判斷主要是利用Class.forName("")進(jìn)行查找胸嘴,如果是Android平臺(tái),會(huì)自定義一個(gè)Executor對象MainThreadExecutor斩祭,并且利用Looper.getMainLooper()實(shí)例化一個(gè)handler對象劣像,在Executor內(nèi)部通過handler.post(runnable),代碼如下:

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

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

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

4)adapterFactories摧玫,這個(gè)對象主要用于對Call進(jìn)行轉(zhuǎn)化耳奕。創(chuàng)建callbackExecutor即MainThreadExecutor對象,MainThreadExecutor
5)converterFactories 轉(zhuǎn)換器工廠诬像,該對象用于轉(zhuǎn)化數(shù)據(jù)屋群,例如將返回的responseBody轉(zhuǎn)化為對象等;當(dāng)然不僅僅是針對返回的數(shù)據(jù)坏挠,還能用于一般備注解的參數(shù)的轉(zhuǎn)化例如@Body標(biāo)識(shí)的對象做一些操作等芍躏。

retrofit.create(Service.class)
  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    ......
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
            ......
          @Override public Object invoke(Object proxy, Method method, Object[] args)
              throws Throwable {
            ......
            ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

分三個(gè)步驟,第一根據(jù)我們的method將其包裝成ServiceMethod降狠,第二通過ServiceMethod和方法的參數(shù)構(gòu)造retrofit2.OkHttpCall對象对竣,第三通過serviceMethod.callAdapter.adapt()方法庇楞,將OkHttpCall進(jìn)行代理包裝;

1>將method包裝成ServiceMethod

下面看Retrofit的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;
  }

可見將method緩存在Map中否纬,所以Retrofit帶有緩存吕晌,第二次網(wǎng)絡(luò)請求相同方法時(shí),會(huì)避免創(chuàng)建實(shí)例化和解析注解临燃,減少響應(yīng)時(shí)間睛驳。

ServiceMethod.build():

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      if (httpMethod == null) {
        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }

      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
    }

1)以上代碼中callAdapter為在Retrofit.Builder.build中platform.defaultCallAdapterFactory(callbackExecutor)創(chuàng)建,在createCallAdapter()中獲取方法的注解和Bean的數(shù)據(jù)類型谬俄,最后調(diào)用ExecutorCallAdapterFactory.get()取出柏靶,callAdapter的作用是將回調(diào)傳遞到UI線程。
2)callAdapter.responseType()返回的是我們方法的實(shí)際類型溃论,例如:Call<User>,則返回User類型屎蜓,然后對該類型進(jìn)行判斷。
3)createResponseConverter()得到responseConverter轉(zhuǎn)換器對象钥勋,它的作用是尋找合適的數(shù)據(jù)類型轉(zhuǎn)換器炬转。在構(gòu)建retrofit時(shí),addConverterFactory添加的ConverterFactory對象來尋找一個(gè)合適的返回,尋找的依據(jù)主要看該converter能否處理你編寫方法的返回值類型算灸,默認(rèn)實(shí)現(xiàn)為BuiltInConverters扼劈,僅僅支持返回值的實(shí)際類型為ResponseBody和Void,也就說明了默認(rèn)情況下菲驴,是不支持Call<User>這類類型的荐吵。

2>通過ServiceMethod和方法的參數(shù)構(gòu)造retrofit2.OkHttpCall對象

OkHttpCall構(gòu)造方法中對方法參數(shù)進(jìn)行賦值

  OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }
3>通過serviceMethod.callAdapter.adapt()方法,將OkHttpCall進(jìn)行代理包裝
serviceMethod.callAdapter.adapt(okHttpCall)

上面說了callAdapter通過CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);獲得赊瞬,而adapterFactories.get(i)得到的call對象是ExecutorCallAdapterFactory先煎。當(dāng)通過retrofit的create()方法再獲得call對象,調(diào)用call.enque()去訪問網(wǎng)絡(luò)時(shí)巧涧,方法中有回掉函數(shù)薯蝎,回掉函數(shù)里重寫兩個(gè)方法,一個(gè)成功谤绳,一個(gè)失斦季狻;這個(gè)call對象其實(shí)就是ExcutorCallAdapterFactory缩筛。callAdapter是ExecutorCallAdapterFactory.get()方法得到的消略。

看return new CallAdapter中的adapt(Call call)我們可以知道,在我們得到接口的代理實(shí)例之后瞎抛,通過代理接口調(diào)用里面的方法疑俭,就會(huì)觸發(fā)InvocationHandler對象中的invoke方法,從而完成上面的三個(gè)步驟并且返回一個(gè)Call對象婿失,通過Call對象就可以去完成我們的請求了钞艇。

從下面代碼可以看出adapt返回的是ExecutorCallbackCall對象。

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
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

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

再看下面代碼可以看出ExecutorCallbackCall是對 Call<T> delegate 的封裝豪硅,delegate 就是OkHttpCall對象哩照,enqueue即是調(diào)用OkHttpCall的方法enqueue而已。

  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) {
      if (callback == null) throw new NullPointerException("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);
            }
          });
        }
      });
    }

再來看OkHttpCall的方法enqueue()方法懒浮,也是調(diào)用okhttp3.Call的enqueue()方法飘弧,下面代碼中可以看到 createRawCall()中對okhttp3.Call初始化;另通過parseResponse()構(gòu)建Response對象砚著。

  @Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("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 {
          //okhttp3.Call call初始化
          call = rawCall = createRawCall();
        } catch (Throwable 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)
          throws IOException {
        Response<T> response;
        try {
          //構(gòu)造Response對象
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

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

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

createRawCall() 中通過serviceMethod.toRequest()構(gòu)造Requset對象次伶,再通過request構(gòu)造call對象。

  private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

parseResponse()是中邏輯為通過serviceMethod對ResponseBody進(jìn)行轉(zhuǎn)化稽穆,然后返回冠王,轉(zhuǎn)化實(shí)際上就是通過responseConverter的convert方法。

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
     ......
    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    T body = serviceMethod.toResponse(catchingBody);
    return Response.success(body, rawResponse);
  }
  R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

好了關(guān)于Retrofit2.0的源碼分析就到這里舌镶,下面總結(jié)一下:
1)首先構(gòu)造retrofit柱彻,核心的參數(shù)是baseurl,callFactory(默認(rèn)okhttpclient)、converterFactories餐胀、adapterFactories哟楷、excallbackExecutor。
2)其次通過create得到接口的實(shí)現(xiàn)類否灾,利用Proxy類完成動(dòng)態(tài)代理的相關(guān)代理卖擅。在我們得到接口的代理實(shí)例之后,通過代理接口調(diào)用里面的方法墨技,就會(huì)觸發(fā)InvocationHandler對象中的invoke方法惩阶,從而完成上面的三個(gè)步驟并且返回一個(gè)Call對象。
3)拿到Call執(zhí)行enqueue或者execute方法健提。
由此Retrofit完成整個(gè)請求回調(diào)流程琳猫。


參考:
Retrofit2 完全解析 探索與okhttp之間的關(guān)系
Retrofi2源碼解析(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市私痹,隨后出現(xiàn)的幾起案子脐嫂,更是在濱河造成了極大的恐慌,老刑警劉巖紊遵,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件账千,死亡現(xiàn)場離奇詭異,居然都是意外死亡暗膜,警方通過查閱死者的電腦和手機(jī)匀奏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來学搜,“玉大人娃善,你說我怎么就攤上這事论衍。” “怎么了聚磺?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵坯台,是天一觀的道長。 經(jīng)常有香客問我瘫寝,道長蜒蕾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任焕阿,我火速辦了婚禮咪啡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暮屡。我一直安慰自己撤摸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布栽惶。 她就那樣靜靜地躺著愁溜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪外厂。 梳的紋絲不亂的頭發(fā)上冕象,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機(jī)與錄音汁蝶,去河邊找鬼渐扮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛掖棉,可吹牛的內(nèi)容都是我干的墓律。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼幔亥,長吁一口氣:“原來是場噩夢啊……” “哼耻讽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起帕棉,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤针肥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后香伴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慰枕,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年即纲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了具帮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蜂厅,靈堂內(nèi)的尸體忽然破棺而出匪凡,到底是詐尸還是另有隱情,我是刑警寧澤葛峻,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布锹雏,位于F島的核電站,受9級(jí)特大地震影響术奖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轻绞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一采记、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧政勃,春花似錦唧龄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至懒叛,卻和暖如春丸冕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背薛窥。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工胖烛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诅迷。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓佩番,卻偏偏與公主長得像,于是被迫代替她去往敵國和親罢杉。 傳聞我的和親對象是個(gè)殘疾皇子趟畏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

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

  • 前言 使用Retrofit已經(jīng)一段時(shí)間了,這貨挺好用的滩租,還很特別赋秀,特別是使用接口來定義請求方式,這用法讓我對它的源...
    帶心情去旅行閱讀 3,359評論 3 21
  • 在開發(fā)Android APP時(shí)持际,肯定會(huì)使用到Http請求與服務(wù)器通信沃琅,上傳或下載數(shù)據(jù)等功能。目前開源的Http請求...
    wangling90閱讀 478評論 0 0
  • 歡迎訪問我的個(gè)人博客 蜘欲,原文鏈接:http://wensibo.net/2017/09/05/retrofit/ ...
    溫斯渤閱讀 421評論 2 3
  • 簡介 剛接觸Retrofit的時(shí)候益眉,就寫了一篇簡單的使用介紹:Retrofit 2.0基本使用方法,算是對Retr...
    Whyn閱讀 2,844評論 4 24
  • 前幾天,和朋友聊天,彼此發(fā)表各自的感慨郭脂。 主要內(nèi)容就是轉(zhuǎn)眼間半輩子過去了年碘,沒有一件拿得出手的戰(zhàn)績。 往往剛開始的幾...
    漿糊郎中閱讀 646評論 2 6