跟我一塊兒看Retrofit 2.0的源碼

跟我一塊兒看Retrofit 2.0的源碼

標籤(空格分隔): Retrofit RxJavajava


背景

Android 6.0(SDK 23)推出後,Apache的HttpClient被棄用。以前一些經常使用的框架如xUtilsandroid-async-http都須要依賴HttpClient,如今用起來都不方便了。幸虧有Retrofit補上這個漏,並且還被得更好。 Retrofit是Square公司出口的一個網絡請求框架,本質上是對OkHttp的包裝,很是適合Android平臺使用。目前最新版本是2.0 beta2,因此下面所說的Retrofit都是指Retrofit 2.0。react

使用樣例

在看源碼以前,咱們先熟悉一下Retrofit的使用方式。下面介紹兩種使用Retrofit的方式,分別是Call<T>方式和RxJava方式。都是基於Gradle。在項目中建立項目以後,android

  • Call<T>方式

在項目的build.gradle文件中添加Retrofit的依賴,git

compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'

建立實體類和一個接口,以下github

public class GithubUser {
    public String login;
    public String avatar_url;
    public String company;
}

public interface GithubApi {
    @GET("users/{user}")
    Call<GithubUser> getUserInfoByName(@Path("user") String name);
}

初創化Retrofit對象,以及實例化GithubApi編程

Retrofit mRetrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/") // 這裏有一個坑,若是項目不是部署在域名根目錄下,則必需要以「/」結尾,不然出錯。在1.9以及以前,url是不能以「/」結尾的。
    .addConverterFactory(GsonConverterFactory.create(gson))
    .client(mClient)
    .build();
    
GithubApi api = mRetrofit.create(GithubApi.class);

而後就能夠請求數據了api

api.getUserInfoByName("atanl").enqueue(new Callback<GithubUser>() {
            @Override
            public void onResponse(Response<GithubUser> response, Retrofit retrofit) {
                Toast.makeText(getApplicationContext(), response.body().login, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Throwable t) {
                t.printStackTrace();
            }
        });

上面代碼涉及了兩個步驟,獲取到一個Call<GithubUser>實例,而後調用它的enqueue方法。其實在前一個步驟http請求是尚未發送的,只有調用的enqueue方法以後纔開始請求。這和java基礎多線程編程中的Call或者Future實際上是一個概念。關於Call<T>下面會有更多說明。緩存

  • 使用RxJava配合的方式

和RxJava配合使用時,本質是對Call<T>這種方式的一個包裝,就是把Call<T>實例轉變成Observable<T>對象。等下作更多的說明,先看一下樣例代碼。ps,若是不知道RxJava是什麼鬼的童鞋,能夠參考給 Android 開發者的 RxJava 詳解網絡

在上面的build.gradle的基礎上再添加下面依賴,多線程

compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'
compile 'io.reactivex:rxandroid:1.0.1'

在生成Retrofit實例的時候,添加一個RxJava的CallAdapterFactory。以下,

Retrofit mRetrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/") // 這裏有一個坑,若是項目不是部署在域名根目錄下,則必需要以「/」結尾,不然出錯。在1.9以及以前,url是不能以「/」結尾的。
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .client(mClient)
    .build();

向GithubApi接口添加一個方法。以下,

public interface GithubApi {

    @GET("users/{user}")
    Call<GithubUser> getUserInfoByName(@Path("user") String name);
    
    GET("users/{user}")
    Observable<GithubUser> getUserInfoObservable(@Path("user") String name);
}

接下下來就是使用這個接口獲取數據了,

api.getUserInfoObservable("atanl")
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(user -> {
        Toast.make(getApplicationContext(), user.login + "", Toast.LENGHT_SHORT).show();
    });

上面代碼中經過getUserInfoObservable獲取獲得的Observable<GithubUser>其實就是經過RxJavaCallAdapterFactory對Call<GithubUser>的一個轉換。

Retrofit create方法的源碼跟蹤

看過上面的樣例,不論是直接經過Call<T>方式仍是和RxJava配合使用,一個必經的步驟應是經過Retrofit的create方法來實例化一個接口實例(如GithubApi)。那麼咱們就一直看一下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, Object... args)
              throws Throwable {
              
              ... 這裏省略了若干行代碼
              
            return loadMethodHandler(method).invoke(args);
          }
        });
  }

上面代碼說白了就是經過Java的動態代理機制,實例化一個實現了GithubApi的的代理客戶端(即Proxy對象),而後調用GithubApi的方法時,操做會被代理到一個InvocationHandler中。如上面代碼,對GithubApi中方法的訪問其實都是代理到了最後一行代碼

return loadMethodHandler(method).invoke(args);

很簡單,意思就是去某個地方獲取一個Handler出來,而後調用它來產生結果,而後做爲接口方法的返回值。那麼咱們繼續跟進loadMethodHandler,看一下load出來的MethodHandler是長什麼樣子的。

MethodHandler<?> loadMethodHandler(Method method) {
    MethodHandler<?> handler;
    synchronized (methodHandlerCache) {
      handler = methodHandlerCache.get(method);
      if (handler == null) {
        handler = MethodHandler.create(this, method); // 這是是關鍵
        methodHandlerCache.put(method, handler);
      }
    }
    return handler;
}

這個方法中能夠看出,Retrofit會先在緩存中找下是否是已經有如今的MethodHandler實例能夠獲取,若是有就直接拿出來用。不然,create一個。咱們先不用管它的緩存,只看create。因此繼續,跟進create方法中,

static MethodHandler<?> create(Retrofit retrofit, Method method) {
    CallAdapter<Object> callAdapter = (CallAdapter<Object>) createCallAdapter(method, retrofit);
    Type responseType = callAdapter.responseType();
    Converter<ResponseBody, Object> responseConverter =
        (Converter<ResponseBody, Object>) createResponseConverter(method, retrofit, responseType);
    RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
    return new MethodHandler<>(retrofit, requestFactory, callAdapter, responseConverter);
  }

這裏有五行代碼,每行都作了一件事。 第一,建立一個CallAdapter,這裏是重點,等下詳述。 第二,獲取到接口(GithubApi)方法的返回值的泛型類型(兩個方法都是GithubUser)。 第三,實例化一個數據結果的轉換器,把Http請求所得的response轉換成POJO。 第四,實例化一個請求工廠類,用於把帶有@GET,@POST等註解的接口方法生成對的Http請求實例。 第五,返回咱們想要的MethodHandler對象。

當咱們拿到MethodHandler對象以後,就能夠調用它的invoke方法來生成結果,而且接口方法的返回值。那麼咱們再看MethodHandler的invoke方法,

Object invoke(Object... args) {
    return callAdapter.adapt(new OkHttpCall<>(retrofit, requestFactory, responseConverter, args)); // 記住這個OkHttpCall類
  }

只是很簡單的調用以前第一步獲取到的CallAdapter實例的adapt方法。方法名很樸實,也很應景,意思就是適配,把一個Call<T>實例(即OkHttpCall<T>對象)適配成一個Call<T>實例(這種狀況下,其實適配器就是直接返回Call<T>實例,沒有作什麼轉換),或者一個Observale<T>實例(這種狀況下,下面細說)。

這裏涉及到兩個關鍵點,一個是CallAdapater,一個是OkHttpCall<T>。後者咱們等下再說,先說CallAdapter。

CallAdapter只是一個接口,不能直接實例化。在Retrofit的體系中,全部的CallAdapter實例都是經過相應的CallAdapterFactory來產生的,如上面提到的RxCallAdapterFactory。

咱們先回到MethodHandler.create方法的第一行代碼,即建立一個CallAdapter。跟進代碼,看一下CallAdapterFactory是怎麼生產出一個CallAdapter來。

private static CallAdapter<?> createCallAdapter(Method method, Retrofit retrofit) {
    Type returnType = method.getGenericReturnType();
    ... // 這裏省略了若干行代碼。
    Annotation[] annotations = method.getAnnotations();
    try {
      return retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { 
      ... // 這裏省略了若干行代碼。
    }
}

////// 
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}

//////
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    ... // 這裏省略了若干行代碼。
    
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

    ... // 這裏省略了若干行代碼。
}

從上面代碼最後的循環中能夠看出,CallAdapter實際上是經過遍歷各個AdapterFactory來,而後根據返回接口方法的返回類型(如上面GithubApi的第二個方法的返回類型是Observable<T>)來決定由哪一個Factory來實例化CallAdapter。若是是返回類型是Observable<T>,那麼就由RxCallAdapterFactory(在建立Retrofit時向其中註冊)來代勞。

RxCallAdapterFactory源碼跟蹤

RxCallAdapterFactory實現了CallAdapter.Factory接口,因此咱們從get方法切入,

@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

    ... // 這裏省略若干行代碼
    
    CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType);
    
    ... // 這裏省略若干行代碼
    
    return callAdapter;
}


private CallAdapter<Observable<?>> getCallAdapter(Type returnType) {
    Type observableType = Utils.getSingleParameterUpperBound((ParameterizedType) returnType);
    
    ... // 這裏省略若干行代碼

    return new SimpleCallAdapter(observableType);
}

上面代碼中,咱們能夠看到,RxCallAdapterFactory最後產生的CallAdapter其實就是一個SimpleCallAdapter實例。它實現了CallAdapter接口,因此咱們也來看一下他的adapt方法。

@Override 
public <R> Observable<R> adapt(Call<R> call) {
    return Observable.create(new CallOnSubscribe<>(call)) //
          .flatMap(new Func1<Response<R>, Observable<R>>() {
            @Override public Observable<R> call(Response<R> response) {
              if (response.isSuccess()) {
                return Observable.just(response.body());
              }
              return Observable.error(new HttpException(response));
            }
          });
}

上面代碼涉及到了一個CallOnSubscribe類,它是Observable.OnSubscribe接口的一個實現。因此咱們來看下它的call方法。

@Override public void call(final Subscriber<? super Response<T>> subscriber) {
      ... // 這裏省略若干行代碼

      try {
        Response<T> response = call.execute();
        if (!subscriber.isUnsubscribed()) {
          subscriber.onNext(response);
        }
      } catch (Throwable t) {
        Exceptions.throwIfFatal(t);
        if (!subscriber.isUnsubscribed()) {
          subscriber.onError(t);
        }
        return;
      }

      if (!subscriber.isUnsubscribed()) {
        subscriber.onCompleted();
      }
}

上面代碼意思很明顯,調用Call<T>的execute方法訪問網絡數據,而且把結果轉化爲Observable的數據源。

好,到這裏RxCallAdapterFactory的工做原理已經知道了,可能有童鞋會對Call<T>接口還有疑問。沒有問題,下面就來看一個Call<T>的實現類——OkHttpCall<T>。

OkHttpCall類的源碼跟蹤

以前有說過Retrofit其實就是對OkHttp的一個包裝。空穴來風,從這個OkHttpCall類就能夠緣由。OkHttpCall類是Call接口一個實現,採起了委派模式,調用它的execute方法或者enqueue方法其實都是委派到com.squareup.okhttp.Call實例來實現,而後再把結果包裝成POJO形式的Response。如execute方法的源碼,

public Response<T> execute() throws IOException {
    synchronized (this) {
    ... // 這裏省略若干行代碼
    com.squareup.okhttp.Call rawCall = createRawCall();
    
    ... // 這裏省略若干行代碼

    return parseResponse(rawCall.execute());
}

private Response<T> parseResponse(com.squareup.okhttp.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    
    ... // 這裏省略若干行代碼
    
    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      ... // 這裏省略若干行代碼
    }
}

另外,Call<T>接口的enqueue方法其實和execute是差很少的,只不過是多線程方式運行。源碼本身去看,要跟蹤到OkHttp的Call<T>中,我懶得寫了。

沒有了

打完收工。

聲明

By 啪嗒科技 atanl ©啪嗒科技 本文只可引用,不容許轉載,只能在發表於padakeji.com相關域名。

相關文章
相關標籤/搜索