跟我一块儿看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相关域名。

相关文章
相关标签/搜索