码迷,mamicode.com
首页 > 其他好文 > 详细

Retrofit2源码解析

时间:2016-06-21 06:54:16      阅读:363      评论:0      收藏:0      [点我收藏+]

标签:

  最近项目将网络框架换成Retrofit2.0.2,文中说的Retrofit都是指的Retrofit2这里要说明一下,毕竟和Retrofit1差别还是蛮大的,结合Okhttp,RxJava还是比较好用的,网上有很多前辈介绍过使用方法,本文是想研究一下Retrofit的源码。关于Retrofit的介绍可以查阅Retrofit的官方网站
  直接进入主题:(注本文是结合RxJava介绍的,最好可以了解一下RxJava不了解也没有关系,大部分的思想是一样的)
  Retrofit的基本使用
  Retrofit使用是非常简单的,在上边的官网上介绍的也非常详细。但是为了后边的分析,还是把使用的代码贴在这儿:
  一般在项目中会将需要请求网络方法写在一个接口中,如下:

 public interface GitHubService {
    @GET("users/{user}/repos")
    Observable<List<Repo>> listRepos(@Path("user") String user);
 }

  如果要使用Retrofit还需要构建Retrofit的对象:

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build();

  主要就是配置baseUrl,ConverterFactory,CallAdapterFactory。这里用的是Gson,和RxJava所以相应的就是GsonConverterFactoryRxJavaCallAdaperFactory这个在后边的源码分析中会用到。
  最后直接调用就可以了:
  

GitHubService service = retrofit.create(GitHubService.class);

service.listRepos("octocat")
              .observeOn(AndroidSchedulers.mainThread())
              .subscribeOn(Schedulers.io())
              .subscribe(list->{
              if(list!=null){
              //TODO 取得数据后逻辑处理
              }
             });

  可以说,代码还是非常简洁的。用起来也很容易上手。
  Retrofit工作流程
  如上面的使用中我们可以看到:
1.通过Retrofit.Builder().build()构建Retrofit实例。
2.调用Retrofit的create()方法将生成接口GitHubService的实例。
3.调用GitHubService的listRepos()方法返回Observable<List<Repo>>,这里的GitHubService实例实际上是个代理对象,这个下文再说。
  下图是我整理的Retrofit运行时主要节点的时序图,当然不是所有的过程都反映出来了。
  技术分享
  看不懂没关系,一步一步来,先看看Retrofit源码的构成:
    

技术分享
 
  简单的介绍一下
  1.Call(接口)–向服务器发送请求并返回响应的调用
  2.CallAdapter(接口)–Call的适配器,用来包装转换Call
  3.CallAdapter.Factory(接口)–CallAdapter的工厂,通过get方法获取对应的CallAdapter
  4.CallBack(接口)–Call的回调
  5.Converter(接口)–数据转换器,将一个对象转化另外一个对象
  6.Converter.Factory(抽象类) – 数据转换器Converter的工厂
  responseBodyConverter – 将服务器返回的数据转化ResponseBody。
  requestBodyConverter – 将GitHubService.listRepos()中的Body,Part等注解转换为RequestBody(),以便Okhttp请求的时候使用。
  stringConverter – 将Field,FieldMap 值,Header,Path,Query,和QueryMap值转化为String,以便Okhttp请求的时候使用。
  7.ServiceMethod 通过解析注解,传参,会将你的接口方法调用转化为一个 Call 对象。也就说对于每一个接口方法,他都会创建一个与之对应的 ServiceMethod
  另外retrofit还有一个http包,都是用来定义 HTTP 请求的自定义注解。如果对注解不太熟悉可以看看我的ButterKnife源码剖析 关于注解的介绍。
  
 
技术分享
 

  回到上边步骤2,调用Retrofit的create()方法将生成接口GitHubService的实例:
  

GitHubService service = retrofit.create(GitHubService.class);

  将GithubService.class作为参数,传入create(),然后又返回一个GithubService实例,看起来是不是很神奇。源码如下:
  

 @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  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() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, 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);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

  这里使用了动态代理,返回了一个 Proxy 代理类,调用GithubService(在自己的项目中是XXXService接口)接口中的任何方法都会调用 proxy 里的 invoke 方法。这个方法里边最重要的就是第23,24,25行代码。
  1.构建ServiceMethod实例
  先看第23行

 ServiceMethod serviceMethod = loadServiceMethod(method);

  通过loadServiceMethod方法获取ServiceMethod实例:
  

ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

  第4行首先会先尝试从serviceMethodCache(类型Map<Method, ServiceMethod>)中get,如果缓存中没有则构建一个ServiceMethod实例。接着看怎么构建ServiceMethod实例,ServiceMethod.java中源码:

public Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

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

  使用Builder模式来构建serviceMethod实例,将retrofit实例,和invoke的方法作为参数来初始化。第10行通过调用createCallAdapter()创建CallAdapter实例callAdapter。

 private CallAdapter<?> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }

  看第11行,获取到了,接口方法中使用的注解,在我们本文中的GithubService的listRepos的注解就是@Get();第13行会通过调用Retrofit的callAdapter()方法来返回CallAdapter实例:
  Retrofit.java文件中:
  

/**
   * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
   * #callAdapterFactories() factories}.
   *
   * @throws IllegalArgumentException if no call adapter available for {@code type}.
   */
  public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

  /**
   * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
   * #callAdapterFactories() factories} except {@code skipPast}.
   *
   * @throws IllegalArgumentException if no call adapter available for {@code type}.
   */
  public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

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

    StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
        .append(returnType)
        .append(".\n");
    if (skipPast != null) {
      builder.append("  Skipped:");
      for (int i = 0; i < start; i++) {
        builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
      }
      builder.append(‘\n‘);
    }
    builder.append("  Tried:");
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }

  真的实现是在Retrofit.java中的nextCallAdapter()方法中实现的。上边代码第25行,adapterFactories是一个缓存CallAdapter.Factory的list,我们在构建Retrofit实例时,曾经设置过addCallAdapterFactory(RxJavaCallAdapterFactory.create()),也就意味着adapterFactories.get(i)将获得到RxJavaCallAdapterFactory,然后会执行其get()方法。
  RxJavaCallAdapterFactory.java文件中:
  

 @Override
  public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);
    String canonicalName = rawType.getCanonicalName();
    boolean isSingle = "rx.Single".equals(canonicalName);
    boolean isCompletable = "rx.Completable".equals(canonicalName);
    if (rawType != Observable.class && !isSingle && !isCompletable) {
      return null;
    }
    if (!isCompletable && !(returnType instanceof ParameterizedType)) {
      String name = isSingle ? "Single" : "Observable";
      throw new IllegalStateException(name + " return type must be parameterized"
          + " as " + name + "<Foo> or " + name + "<? extends Foo>");
    }

    if (isCompletable) {
      // Add Completable-converter wrapper from a separate class. This defers classloading such that
      // regular Observable operation can be leveraged without relying on this unstable RxJava API.
      // Note that this has to be done separately since Completable doesn‘t have a parametrized
      // type.
      return CompletableHelper.createCallAdapter(scheduler);
    }

    CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);
    if (isSingle) {
      // Add Single-converter wrapper from a separate class. This defers classloading such that
      // regular Observable operation can be leveraged without relying on this unstable RxJava API.
      return SingleHelper.makeSingle(callAdapter);
    }
    return callAdapter;
  }

  正常情况下,会执行到第27行,通过getCallAdapter方法,获得Observable泛型的CallAdapter,继续跟进去看看:
  

 private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
    Class<?> rawObservableType = getRawType(observableType);
    if (rawObservableType == Response.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Response must be parameterized"
            + " as Response<Foo> or Response<? extends Foo>");
      }
      Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
      return new ResponseCallAdapter(responseType, scheduler);
    }

    if (rawObservableType == Result.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Result must be parameterized"
            + " as Result<Foo> or Result<? extends Foo>");
      }
      Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
      return new ResultCallAdapter(responseType, scheduler);
    }

    return new SimpleCallAdapter(observableType, scheduler);
  }

  第3行会getRawType(observableType)会返回Observable具体类型,例如本例中,

 public interface GitHubService {
    @GET("users/{user}/repos")
    Observable<List<Repo>> listRepos(@Path("user") String user);
 }

  返回值是Observable<List<Repo>> 那么getRawType(observableType)将得到List.class,这样程序将执行第22行,将返回一个SimpleCallAdapter实例,那么它就是CallAdapter的真正实现。
  回到ServiceMethod的build()方法中,继续执行第18行responseConverter = createResponseConverter();过程也和createCallAdapter差不多,也是使用工厂模式,通过get()方法获得Converter的真正实现,篇幅所限就不一步一步的跟了,本例使用的是Gson,所以Converter得实现是GsonResponseBodyConverter。之后就是解析注解,参数等,这样ServiceMethod已经构建好了。
  
  生成OkHttpCall
  回到Retrofit动态代理invoke方法中,第二步就是生成Call的实例了,目前Retrofit的默认使用的是OkhttpCall。其是OkHttp的包装类,所有OkHttp需要的参数都在该类中找到。

  adapt Call
  第三步执行serviceMethod.callAdapter.adapt(okHttpCall),通过之前的分析,serviceMethod.callAdapter真正的实现是SimpleCallAdapter,那么自然也是执行的它的adapt()方法。为了证实这个,可以debug一下就知道了。
  技术分享

  RxJavaCallAdapterFactory.SimpleCallAdapter.adapt():
  

@Override public <R> Observable<R> adapt(Call<R> call) {
      Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) 
          .lift(OperatorMapResponseToBodyOrError.<R>instance());
      if (scheduler != null) {
        return observable.subscribeOn(scheduler);
      }
      return observable;
    }
  }

  其返回类型Observable,也就是我们需要的结果,还记得我们是怎么使用的RxJava的吗?
  

service.listRepos("octocat")
              .observeOn(AndroidSchedulers.mainThread())
              .subscribeOn(Schedulers.io())
              .subscribe(list->{
              if(list!=null){
              //TODO 取得数据后逻辑处理
              }
             });

  看代码service.listRepos(“octocat”)应该是一个Observable,而刚刚分析的,service.listRepos(“octocat”)确实会返回一个Observable,有了这个Observable之后,我们就可以通过subscribeOn给他指定运行线程,这样像网络请求耗时操作就不会再UI线程中运行,从而达到异步的目的,然后通过observeOn()将线程切回UI线程,当Okhttp请求完数据并进行相应的convert之后,就可以在UI处理相应的逻辑。
  回到adapt方法,第2行创建Observable,而new CallOnSubscribe<>(call)生成了一个OnSubscribe()的实例,而OnSubscribe继承自Action1,其只包含一个call()方法,而这个call是在CallOnSubscribe中实现:
  

static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
    private final Call<T> originalCall;

    CallOnSubscribe(Call<T> originalCall) {
      this.originalCall = originalCall;
    }

    @Override public void call(final Subscriber<? super Response<T>> subscriber) {
      // Since Call is a one-shot type, clone it for each new subscriber.
      Call<T> call = originalCall.clone();

      // Wrap the call in a helper which handles both unsubscription and backpressure.
      RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber);
      subscriber.add(requestArbiter);
      subscriber.setProducer(requestArbiter);
    }
  }

  首先clone了一份Call,然后生成了RequestArbiter,他继承自AtomicBoolean,实现了Subscription, Producer接口,Producer只有一个request方法;一般实现该接口的类,都会包含一个Subscriber对象和一个待处理的数据:
  

static final class RequestArbiter<T> extends AtomicBoolean implements Subscription, Producer {
    private final Call<T> call;
    private final Subscriber<? super Response<T>> subscriber;

    RequestArbiter(Call<T> call, Subscriber<? super Response<T>> subscriber) {
      this.call = call;
      this.subscriber = subscriber;
    }

    @Override public void request(long n) {
      if (n < 0) throw new IllegalArgumentException("n < 0: " + n);
      if (n == 0) return; // Nothing to do when requesting 0.
      if (!compareAndSet(false, true)) return; // Request was already triggered.

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

    @Override public void unsubscribe() {
      call.cancel();
    }

    @Override public boolean isUnsubscribed() {
      return call.isCanceled();
    }
  }

  那么看看request()方法到底干了什么?第16行代码call.execute()最终将执行okhttp的execute(),为什么这里会同步请求数据呢,还记得之前我们把耗时操作切换到子线程中吗?既然已经不是在UI线程了,这里就可以使用同步获取response数据了。在获取到response后就通过执行subscriber.onNext(response);这样subscribe过Observable的subscriber都可以收到数据了。而因为我们设置过observeOn(AndroidSchedulers.mainThread()),所以当我们接受到数据的时候,已经是在UI线程中了,所以就可以做后续的逻辑处理了。
  总结:Retrofit 的代码并不是很多,其底层网络通信时交由 OkHttp 3来完成的,但是Retrofit运用了大量的设计模式,代码逻辑很清晰。没事的时候,不妨研究研究,毕竟是Jake Wharton大神的杰作。
  

Retrofit2源码解析

标签:

原文地址:http://blog.csdn.net/chenkai19920410/article/details/51719425

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!