为了账号安全,请及时绑定邮箱和手机立即绑定

快速上手Retrofit框架

标签:
Android

看过很多篇 Retrofit 的源码分析文章但是别人一问起来总是讲不清楚到底 Retrofit 是怎么个流程所以还是得自己亲自去看看源码一步一步的分析。果然只有亲自动手实践才有自己的收获。
告诫自己慢慢来会很快。

Retrofit 简介

Retrofit 源码开头的解释

* Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to
* define how requests are made. Create instances using {@linkplain Builder
* the builder} and pass your interface to {@link #create} to generate an implementation.

Retrofit 利用方法上的注解将接口转化成一个 HTTP 请求。

简单知道是什么了之后我们对此提出疑问

§  如何将接口转换为网络请求

§  谁去进行网络请求

接下来我们将从 Retrofit 的使用作为入口分析。

Retrofit 分析

具体使用

首先建立 API 接口类

interface GankApi {
    String host = "http://gank.io/api/data/";
    @GET("Android/10/{page}")
    Call<Android> getAndroid(@Path("page") int page);
}

 

// 创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(GankApi.host)
    .addConverterFactory(GsonConverterFactory.create())
    .build();
// 生成接口实现类
GankApi gankApi = retrofit.create(GankApi.class);
// 调用接口定义的请求方法并且返回 Call 对象
Call<Android> call = gankApi.getAndroid(1);
// 调用 Call 对象的异步执行方法
call.enqueue(Callback callback)

简单的使用就是这样的流程。现在我们开始层层剖析。

工具箱Retrofit.Builder()

private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;

创建 Retrofit 的实例进行一些配置这里我们不用多说。但是有一个参数必须得讲讲。

§  Platform

在构建 Retrofit 的时候会对当前使用平台进行判断Java8AndroidiOS。

我们看看 Android 平台的代码

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.      在 Android 里我们默认使用的 CallAdapter 是 ExecutorCallAdapterFactory() 它会返回的是 Call.class。关于 ExecutorCallAdapterFactory() 我们稍后再说你先知道这是 Android 默认 CallAdapter 就好。

5.    默认的 Callback 是在主线程。

外壳Create()

// 生成接口实现类
GankApi gankApi = retrofit.create(GankApi.class);

我在源码里写好了注释

public <T> T create(final Class<T> service) {
    // 检查传入的类是否为接口并且无继承
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    // 重点是这里
    // 首先会返回一个利用代理实现的 GankApi 对象
    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);
            }
            // 解析方法 这里用到了注解Runtime这里我们标记下A稍后来看看里面具体实现
            ServiceMethod serviceMethod = loadServiceMethod(method);
            // 将刚刚解析完毕包装后的具体方法封装成 OkHttpCall 你可以在该实现类找到 okhttp 请求所需要的参数
            // 所以它是用来跟 okhttp 对接的。
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            // 将以上我们封装好的 call 返回给上层这个时候我们就可以执行 call 的同步方法或者异步进行请求。
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

切合我们实际运用来看看顺序

GankApi gankApi = retrofit.create(GankApi.class);—->
return (T) Proxy.newProxyInstance...{...}—->
Call<Android> call = gankApi.getAndroid(1); —->
public Object invoke(...){...} 调用代理类的invoke()

直到这里我们已经宏观地了解 Retrofit 是怎样的一个流程。
达成 初窥门径 成就。

千万别骄傲为了以后走的更远更稳我们得好好筑基上面我们用到的是动态代理强烈建议认真阅读两篇文章。

§  Retrofit2源码分析[动态代理]

§  Java静态代理和动态代理

结构ServiceMethod

Retrofit 有一个双链表用来缓存方法
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();

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

我们发现主要的方法是 new ServiceMethod.Builder(this, method).build(); 所以接下来我们深入看看如何 解析注解 以及 构建请求方法 。

§  初始化一些参数

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

§  build()

这里的源码很长做了很多异常处理我截取重点来分析下。

callAdapter = createCallAdapter();
responseConverter = createResponseConverter();

一个是用来发送请求的 client 一个是结果的转换器GsonFastJson …之类后面我们再讲这个。
上层配置就是当我们调用 Retrofit 的 addConverterFactory()和 addCallAdapterFactory()内部会自动使用我们定义的组件。

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

在这里可以看到遍历我们使用方法的注解并且解析他们。parseMethodAnnotation() 内部就是解析好 HTTP 的请求方式。

为了篇幅大小可以在 源码 里看看具体的操作。

同时也可以看看 http 包下注解用到的接口你会发现 @Retention(RUNTIME) 所以从这里我们就可以明白Retrofit 是在在运行期通过反射访问到这些注解的。

§  return Call

请求方法参数请求客户端返回值转换我们都定义好了之后便完成最后一步构建好适合请求客户端的请求方法Retrofit 默认的是 okhttpCall 。

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

最后将 call 返回给上层用户调用方法进行请求。

§  总结

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

ServiceMethod 类开头注释已经很清楚的说明了作用将接口方法改变成一个 HTTP call 。它对于 Retrofit 是很重要的存在整个枪支内部都是由它来支撑起来。

子弹xxxFactory()

Retrofit 给我们最大的便利就是自身框架优雅的设计只需要很小的改动便可以优雅的适应不同的需求。所以很需要我们再补充点额外知识了解什么是适配器模式然后回到这里看看 Retrofit 是如何应用的。

在构建 ServiceMethod 对象的时候有三个方法可以单独说说

12.  build() 中 createCallAdapter() —-> retrofit.callAdapter()

13.  解析接口方法内注解时parseParameterAnnotation()调用到的retrofit.requestBodyConverter()

14.  build() 中 createResponseConverter() —-> retrofit.responseBodyConverter()

callAdapter()

最终会调用到 nextCallAdapter() 该方法主要是从 callAdapterFactories 中获取新的 CallAdapter它会跳过 skipPast以及 skipPast 之前的 Factory然后找到与 returnType 和 annotations 都匹配的 CallAdapterFactory 。

requestBodyConverter() & responseBodyConverter()

最终会调用到 nextRequestBodyConverter()/nextResponseBodyConverter利用 converterFactories 创建一个与 RequestBody/ResponseBody 对应的 Converter 对象。

所以在这里我们就可以装填我们需要的子弹类型了。

进入实战为我们的 Retrofit 添加 RxJava Gson

§  Rxjava:

          5badd16b000147f611700306.jpg                                    

adapter-rxjava 我们重点看 RxJavaCallAdapterFactory 即可它是实现了 CallAdapter.Factory 并在对应方法里将 Call 包装成 Observable.class 返回。

然后给 Retrofit 对象加上 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())这样我们才可以优雅的使用 Retrofit + RxJava 。

§  Gson:

5badd15b00019a0f11940262.jpg

我相信通过类名我们就可以知道每个类是用来做什么的我在这里太过深入到具体实现反而一叶障目

如果我们需要自定义数据转换格式也是同样这样做。
继承 Converter.Factory 类作为适配类同时创建两个实现 Converter 的类包装请求和响应的数据形式。

开枪打靶: Call.enqueue()

注意我这里只列举一个默认状态下的情况

还记得我工具箱里我们提到的 ExecutorCallbackCall 吗
这里的 Call 是对应我们选择的 call 而此时是默认的 ExecutorCallbackCall 。如果还要问我为什么请去看看 工具箱Retrofit.Builder() 里 Android 平台的源码。

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);
            }
          }
        });
      }
      // 省略
}

这里的 delegate 对应的就是 okhttp 的 call 不禁有疑问了这里调用的是异步请求但是我们的回调是怎么回到主线程的呢

带着疑问我们来看看。
首先回调是在 callbackExecutor.execute() 我们从这里入手。
我们发现在 Retrofit 的 build() 方法里

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
  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);
    }
  }
}

我们发现Android 默认的调度器是主线程的 Handler execute()方法也只是 mainHandler.post() 。

所以这下就可以解决我们的疑问了。

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

这段代码我们就可以改写为

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

如果看到这还不理解为什么那就得好好补补 handler 的知识啦

我这里推荐 melo 写的这篇风趣易懂 带着这篇去通关所有Handler的提问 。

最后放上两张开源社区画的流程图我觉得特别清晰

5badd14400012b4809600720.jpg

原文链接http://www.apkbus.com/blog-705730-62054.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消