Retrofit源码分析

96
乐小文
2017.04.09 12:06* 字数 712

关于Retrofit的使用这里就不再赘述了,还不太了解Retrofit使用的同学
Retrofit简介
今天我们来聊一聊Retrofit的内部实现,通过源码来分析Retrofit的整个执行顺序。

在没有框架的时候,做一次网络请求大概会经过五个步奏:

  • 构建request的参数
  • 手动开启子线程做http请求
  • 在子线程的run方法中具体请求
  • 拿到返回的response数据后,回调给上一层
  • 在主线程中更新UI

如果没有网络请求框架,然后对多线程又不是太熟悉,就会出现很多问题。比如,请求是否异步,这里就会出现android中常见的错误:Null pointer exception。
所以,在我们还没有造轮子的能力的时候,多去看看优秀框架的源码是有好处的,整个框架的搭建,运用了哪些设计模式,容错处理等等。。

Retrofit 获取实例

  • 首先通过构建者模式去获得Retrofit实例
 Retrofit retrofit = new Retrofit
                .Builder()
                .baseUrl(ApiContancts.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
  • 我们来看看build()方法中具体做了什么
 public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

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

不难看出build()方法中主要做了判空处理:
1.baseurl为空,抛出异常;
2.callFactory为空,默认使用OKhttp3的callFactory,这一点也可以看出Retrofit是基于okhttp3做的封装。不会支持URLConnection和OkHttpClient了。
3.callbackExecutor为空,会通过Platform这个类使用defaultCallbackExecutor

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

跟踪源码会发现,最终会通过Handler去做操作。
4.第一个List集合是存储刚刚那个callbackExecutor,第二个List集合是存储将Json转换成实体类的一个工厂或者说是适配器。
5.最后返回一个Retrofit的实例。

Retrofit实例的create()方法

Call<CookListModel> cook = retrofit.create(ApiService.class).getCook(1,20);

通过调用create()方法

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

其实我看到这里也很懵逼,我们的Http请求方法、参数是通过注解的方式创建的,它是怎么转换成实体对象的?
不急,我们一步一步的看下去

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

这里也用了构建者模式,build()方法中调用parseMethodAnnotation()去解析注解

  private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
        if (!Void.class.equals(responseType)) {
          throw methodError("HEAD method must use Void as response type.");
        }
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError("@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }

那么,Retrofit到底是怎么把我们定义的接口转换成http请求的呢?
我们来看看ServiceMethod这个类。

Adapts an invocation of an interface method into an HTTP call.

ServiceMethod这个类相当于一个适配器,将interface转换成http的请求,再通过OkHttp去做网络请求。
所以说,真正的关键代码是:

ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

Retrofit内部大致的执行流程就是这样,如果想要更深入的去研究Retrofit的话,建议大家利用debug一步一步的跟踪源码分析,这样的话会更加容易理解一点。

随笔
Web note ad 1