Retrofit(二)

Android知识总结

一、Retrofit 对Okhttp做了什么

Retrofit并没有改变网络请求的本质,也无需改变,因为Okhttp已经足够强大,Retrofit的封装可以说是很强大,里面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,虽然默认是用http ,可以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava 可以说是目前比较潮的一套框架,但是需要有比较高的门槛。

下面我们来对比一下OKhttp网络请求和 retrofit网络请求的区别。

1.1、Okhttp请求总结

        //Step1
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .build();
        //Step2
        Request request = new Request.Builder()
                .url("https://www.google.com.hk")
                .build();
        //Step3
        okhttp3.Call call = okHttpClient.newCall(request);
        //Step4
        call.enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {

            }

            @Override
            public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {

            }
        });
  • Step1:创建HttpClient对象,也就是构建一个网络类型的实例,一般会将所有的网络请求使用同一个单例对象。
  • Step2:构建Request,也就是构建一个具体的网络请求对象,具体的请求url,请求头,请求体等等。
  • Step3:构建请求Call,也就是将具体的网络请求与执行请求的实体进行绑定,形成一个具体的正式的可执行实体。
  • Step4: 后面就进行网络请求了,然后处理网络请求的数据了。
  • 总结
    OKhttp的意义:OkHttp 是基于Http协议封装的一套请求客户端,虽然它也可以开线程,但根本上它更偏向真正请求,跟HttpClient, HttpUrlConnection的职责是一样的。
    Okhttp的职责:OkHttp主要负责socket部分的优化,比如多路复用,buffer缓存,数据压缩等等。
    Okhttp给用户留下的问题
  • 1)用户网络请求的接口配置繁琐,尤其是需要配置请求body,请求头,参数的时候;
  • 2)数据解析过程需要用户手动拿到responsbody进行解析,不能复用;
  • 3)无法适配自动进行线程的切换。

1.2、Retrofit请求总结

        //Step1
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.google.com.hk")
                 //加入网络请求适配器工厂: rxjava
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                 //加入数据转换器工厂 :gson
                .addConverterFactory(GsonConverterFactory.create(new Gson()))
                .build();
        //Step2
        WifiInterface wifiInterface = retrofit.create(WifiInterface.class);
        //Step3
        Call<Object> wifi = wifiInterface.getWifi();
        //Step4
        wifi.enqueue(new Callback<Object>() {
            @Override
            public void onResponse(Call<Object> call, Response<Object> response) {

            }

            @Override
            public void onFailure(Call<Object> call, Throwable t) {

            }
        });
  • Step1: 创建retrofit对象, 构建一个网络请求的载体对象,和okhttp构建OkhttpClient对象有一样的意义,只不过retrofit在build的时候有非常多的初始化内容,这些内容可以为后面网络请求提供准备,如准备 现成转换Executor,Gson convert,RxJavaCallAdapter。
  • Step2:Retrofit的精髓,为统一配置网络请求完成动态代理的设置。
  • Step3:构建具体网络请求对象Request(service),在这个阶段要完成的任务:
    1)将接口中的注解翻译成对应的参数;
    2)确定网络请求接口的返回值response类型以及对应的转换器;
    3)讲Okhttp的Request封装成为Retrofit的OKhttpCall。
    总结来说,就是根据请求service 的Interface来封装Okhttp请求Request。
  • Step4:后面就进行网络请求了,然后处理网络请求的数据了
  • 终结
    Retrofit主要负责应用层面的封装,就是说主要面向开发者,方便使用,比如请求参数,响应数据的处理,错误处理等等。
    Retrofit封装了具体的请求,线程切换以及数据转换。
    网上一般都推荐RxJava+Retrofit+OkHttp框架,Retrofit负责请求的数据和请求的结果,使用接口的方式呈现,OkHttp负责请求的过程,RxJava负责异步,各种线程之间的切换,用起来非常便利。

1.3、小结

通过下图,让我们来总结一下,retrofit是如何来封装okhttp请求的。


大体的网络流程是一致的,毕竟都是通过okhttp进行网络请求。主要的步骤都是:创建网络请求实体client->构建真正的网络请求-> 将网络请求方案与真正的网络请求实体结合构成一个请求Call->执行网络请求->处理返回数据->处理Android 平台的线程问题。

在上图中,我们看到的对比最大的区别是什么?

  • 0)okhttp创建的是OkhttpClient,然而retrofit创建的是 Retrofit实例
  • 1)构建蓝色的Requet的方案,retrofit是通过注解来进行的适配
  • 2)配置Call的过程中,retrofit是利用Adapter适配的Okhttp 的Call
  • 3)相对okhttp,retrofit会对responseBody进行 自动的Gson解析
  • 4)相对okhttp,retrofit会自动的完成线程的切换。

二、Retrofit的构建过程

retrofit 总流程

2.1、代理实例创建过程

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://www.google.com.hk")
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .addConverterFactory(GsonConverterFactory.create(new Gson()))
        .build();

1: 成功建立一个Retrofit对象的标准:配置好Retrofit类里的成员变量

  • baseUrl:网络请求的url地址
  • callFactory:网络请求工厂,默认为OKHttpCall
  • callbackExecutor:回调方法执行器,Android平台默认为MainThreadExecutor
  • adapterFactories:网络请求适配器工厂的集合,返回对应的 Call
  • converterFactories:数据转换器工厂的集合
代理实例创建详情

2.2、build 过程

Retrofit #build类中进行构建。

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      // 代码1
      //默认只支持okhttp请求,不支持 httpurlconnection 和 httpclient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      // 代码2
      // 添加一个线程管理 Executor,okhttp 切换线程需要手动操作,但是retrofit不需要,
      // 就是因为这个Executor 的存在,其实他是handler。默认为MainThreadExecutor
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

       // 代码3
      //添加网络请求适配器,如果自己设置网络适配器用自己设置的,否则用默认的
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      //添加数据转换器集合
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
      //代码 4
      //将builder中的数据给Retrofit
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

2.2.1、在代码 1 处

初始化 构建call 的工厂,但是这个地方直接就是使用了 okhttp的call,没有使用到工厂设计模式去添加构建httpclient 或者 httpurlconnection的方法来创建 call,说明retrofit 已经铁下心只支持okhttp创建call请求了。
那么call 是什么的抽象呢?看下面的代码,okhttp请求的代码

OkHttpClient client = new OkHttpClient.Builder().
        readTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder().
        url("http://www.baidu.com").get().build();
okhttp3.Call call = client.newCall(request);
call.enqueue(new okhttp3.Callback() )...

OkHttpClient是 http 请求的载体包含socket等可以复用的对象,协议配置等等一切。
Request 创建的是一个具体的有url,header,等请求信息的一个网络请求,表示这个具体的请求。
Call 通往请求的,去执行请求的整个过程的一个抽象。也是进行网络请求的最终接口。
所以,此次调用,目的就是创建了一个OkHttpClient,换句话说,这里的调用就是生产 Okhttp网络请求需要的请求Call的,以备后面进行真正的网络请求。

2.2.2、在代码 2 处

网络请求需要在子线程中执行,那么就需要线程管理,所以就有了代码2的存在,深入源码后发现,这个地方就是运用handler进行线程切换,当网络请求回来了进行线程切换,可以看下面的源码

Platform#defaultCallbackExecutor中我们可以看到,此方法反回空。

  @Nullable Executor defaultCallbackExecutor() {
    return null;
  }

真么回事,然后我们继续跟踪 Platform 的子类,我们发现其实在子类中实现的。
Retrofit#Builder类中的构造方法中回传入Platform,通过Platform.get()获取。

  //用于生成一个请求结果回调器
  private final Platform platform;
  //网络请求工厂
  private @Nullable okhttp3.Call.Factory callFactory;
  //网络请求的主路径,必须以”/“结尾
  private @Nullable HttpUrl baseUrl;
  //请求结果数据转换器,把服务端返回的数据通过转换器转换为对象,如:GsonConvertFactory.create()
  private final List<Converter.Factory> converterFactories = new ArrayList<>();
  //网络请求适配器,如:适配OkHttp的call,以及RxJava的Observable
  private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
  //网络请求结果回调器
  private @Nullable Executor callbackExecutor;
  //是否提前对业务接口中的注解进行转换,这个在retrofit中会用到
  private boolean validateEagerly;

  Builder(Platform platform) {
    this.platform = platform;
  }

  public Builder() {
    this(Platform.get());
  }

然后看Platform中的单例模式
Retrofit中用来管理多平台的方法,支持Android、Java8。通过findPlatform获取对应的平台,同时也初始化了defaultCallAdapterFactory工厂

  private static final Platform PLATFORM = findPlatform();
  //Platform对象的get方法返回了一个请求结果回调器,
  //表明这个请求结果在主线程中运行
  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        //通过单例创建 Platform 的子类
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

通过Platform#Android类中的静态内部类 MainThreadExecutor来创建handler 来进行线程切换。

  static class Android extends Platform {
    //请求结果回调,使请求结果在主线程中执行
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      ////根据主线程的 Looper 创建 handler
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        //在主线程执行Runnable,这里的r指的就是请求结果的回调方法
        handler.post(r);
      }
    }
  }

然后我们看默认的 ExecutorCallAdapterFactory的执行流程

public class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    final Executor callbackExecutor;

    //默认为MainThreadExecutor
    ExecutorCallAdapterFactory(Executor callbackExecutor) {
        this.callbackExecutor = callbackExecutor;
    }

    //创建CallAdapter,运用工厂设计模式
    @Override
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Object, Call<?>>() {
            @Override
            public Type responseType() {
                return responseType;
            }

            //返回了一个 ExecutorCallbackCall 对象
            @Override
            public Call<Object> adapt(Call<Object> call) {
                return new ExecutorCallAdapterFactory.ExecutorCallbackCall<>(callbackExecutor, call);
            }
        };
    }

    //而ExecutorCallbackCall对象实现了Call类并实现了其enqueue、execute以及request方法
    //运用装饰者模式,对其进行加强加入线程切换
    static final class ExecutorCallbackCall<T> implements Call<T> {
        //默认为MainThreadExecutor
        final Executor callbackExecutor;
        //网络请求的委托实例,实际执行者是 okHttpCall。运用静态代理模式
        final Call<T> delegate;

        ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
            this.callbackExecutor = callbackExecutor;
            this.delegate = delegate;
        }

        @Override
        public void enqueue(final Callback<T> callback) {
            checkNotNull(callback, "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()) {
                                //用handler封装的Executor, 进行切换线程
                                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                                callback.onFailure(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, new IOException("Canceled"));
                            } else {
                                callback.onResponse(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, response);
                            }
                        }
                    });
                }

                @Override
                public void onFailure(Call<T> call, final Throwable t) {
                    //用handler封装的Executor, 进行切换线程
                    callbackExecutor.execute(new Runnable() {
                        @Override
                        public void run() {
                            callback.onFailure(ExecutorCallAdapterFactory.ExecutorCallbackCall.this, t);
                        }
                    });
                }
            });
        }

        @Override
        public boolean isExecuted() {
            return delegate.isExecuted();
        }

        @Override
        public Response<T> execute() throws IOException {
            return delegate.execute();
        }

        @Override
        public void cancel() {
            delegate.cancel();
        }

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

        @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
        @Override
        public Call<T> clone() {
            return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
        }

        @Override
        public Request request() {
            return delegate.request();
        }
    }
}

所以,此次调用,目的是构建一个用handler封装的Executor,以备后面进行网络请求成功后的线程切换用。

2.2.3、在代码 3 处

设置默认CallAdapterFactory
在此添加的CallAdapterFactory属于系统默认的,当然,我们可以添加RxJavaCallAdapterFactory。默认的CallAdapterFactory是 ExecutorCallAdapterFactory 类的对象,在Platform.java Class里面可以梳理出来,当默认的线程切换用此默认适配器。

  CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor != null) {
      //添加默认的 Factory ,用于把 rxjava#call 转换的 retrofit#call
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

所以构建的Retrofit都是用于进行后面请求的需要的内容的一个准备工作。也就是封装Okhttp需要的准备工作。

2.2.4、在代码四处

Retroft把一个java接口的抽象方法 适配/转化 成一个HTTP的请求,它内部是使用解析接口内部的抽象方法上的注解来定义如何去发起请求。通过Builder可以创建Retroft的实例,通过调用create()方法来创建一个接口的具体实现类。

public final class Retrofit {
  //serviceMethod对象集合的缓存,用于重用,由于里面用到了反射,大家知道反射比较消耗
 //性能,所以为了避免重复反射,节约性能,使用缓存,保证只反射一次。
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
  final okhttp3.Call.Factory callFactory;
  final HttpUrl baseUrl;
  //数据转换器工厂的集合
  final List<Converter.Factory> converterFactories;
  // 网络请求适配器工厂的集合
  final List<CallAdapter.Factory> adapterFactories;
  // 回调的线程池,默认切换到主线程
  final @Nullable Executor callbackExecutor;
  //如果为true,程序是在做一个预处理的操作,只是提前创建了一些MethodHandler对象在缓存中。
  final boolean validateEagerly;

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
    this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }
...
}

三、创建过程

3.1、代理实例创建过程

WifiInterface wifiInterface = retrofit.create(WifiInterface.class);

创建了一个WifiInterface 接口类的对象,create函数内部使用了动态代理来创建接口对象,这样的设计可以让所有的访问请求都被代理。

3.2、访问接口创建过程

Call<Object> wifi = wifiInterface.getWifi()

调用getWifi的时候,在动态代理里面,会存在一个函数 getWifi,这个函数里面会调用 invoke,这个invoke函数也就是retrofit里面 invoke函数。

所以,动态代理可以代理所有的接口,让所有的接口都走 invoke函数,这样就可以拦截调用函数的执行,从而将网络接口的参数配置归一化

3.3、创建流程

整个调用流程图
简化流程图
    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, @Nullable 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放入在缓存中,
                        //如果已经生成过则直接从缓存中获取
                        ServiceMethod<Object, Object> serviceMethod =
                                (ServiceMethod<Object, Object>) loadServiceMethod(method);
                        // 根据ServiceMethod对象和请求参数生成一个OkHttpCall对象,这个OkHttpCall能够
                        //调用OkHttp的接口发起网络请求
                        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                        // 调用serviceMethod的callAdapter的adapt方法,并传入okHttpCall,返回一个对象,
                        //这个的目的主要是为了适配返回类型,其内部会对OkhttpCall对象进行包装
                        return serviceMethod.callAdapter.adapt(okHttpCall);
                    }
                });
    }

终结:

  • 1)Retrofit的create方法通过动态代理的模式,生成了实现了具体的网络请求接口的对象,并在InvocationHandler的invoke方法中统一处理网络请求接口实体对象的方法;
  • 2)invoke方法会通过方法构造一个ServiceMethod对象,并将其放入缓存中;
  • 3)然后根据ServiceMethod对象和网络请求的参数args去构造一个OkHttpCall对象;
  • 4)最后调用serviceMethod的callAdapter的adapt方法,传入将OkHttpCall对象,callAdapter的目的主要是为了适配OkHttpCall对象,其内部会对OkHttpCall对象进行包装,生成对应返回类型的对象。

3.3.1、动态代理

动态代理的原理主要是在运行时动态生成代理类,然后根据代理类生成一个代理对象,在这个代理对象的方法中中又会调用InvocationHandler的invoke来转发对方法的处理。

那么大家一定要关注一个细节,我们在使用retrofit的时候,对每一个网络请求的产生都必须要先调用create函数,也就是意味着,我们的请求都是通过代理类来进行处理的。但是代理类具体的代理行为是发生在哪里呢?很显然,他并不是在create函数执行的时候,而是在使用具体的接口创建具体网络请求Call的时候,当调用具体网络请求Call的代码示例如下:

Call<Object> wifi = wifiInterface.getWifi();

在执行上面的代码的时候,它会走代理设计模式的InvocationHandler里面的invoke()函数,也就是所有的网络请求在创建具体网络请求Call的时候,都会走Invoke,从而我们可以在invoke里面进行各种行为的统一处理,比如:接口的统一配置,也就是注解的解读和网络请求参数的拼接。

3.3.2、ServiceMethod 创建

看执行Retrofit#loadServiceMethod的方法:

public final class Retrofit {
  //serviceMethod对象集合的缓存,用于重用,由于里面用到了反射,大家知道反射比较消耗
 //性能,所以为了避免重复反射,节约性能,使用缓存,保证只反射一次。
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
  final okhttp3.Call.Factory callFactory;
  final HttpUrl baseUrl;
  //数据转换器工厂的集合
  final List<Converter.Factory> converterFactories;
  // 网络请求适配器工厂的集合
  final List<CallAdapter.Factory> adapterFactories;
  // 回调的线程池,默认切换到主线程
  final @Nullable Executor callbackExecutor;
  //如果为true,程序是在做一个预处理的操作,只是提前创建了一些MethodHandler对象在缓存中。
  final boolean validateEagerly;
  ...

  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    //设置了一个线程同步锁,主要是为了保证我们的线程的数据安全。
    synchronized (serviceMethodCache) {
      /**
       * 获取到我们的ServiceMethod,这个ServiceMethod采用的是单例模式进行创建的,
       * 它其实有一个serciveMethodCache缓存池进行获取。
       */
      result = serviceMethodCache.get(method);
      /**
       * 非空判断。如果没有缓存就自己创建一个ServiceMethod对象,
       * 它是通过构建者模式Builder来进行创建的。
       */
      if (result == null) {
        // 最终调用build()来创建我们实际的ServiceMethod对象的创建。
        result = new ServiceMethod.Builder<>(this, method).build();
        /**
         * 放到缓存池当中,以HTTP请求方法做为KEY,
         * ServiceMethod这个对象做为VALUES,保存在这个缓存池当中。
         */
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
 ...
}
  • 由上可得:

loadServiceMethod首先会从缓存中获取ServiceMethod对象,如果没有,则通过Method和Retrofit对象构造一个ServiceMethod对象,并将其放入缓存中。

每一个method 都有一个自己的ServiceMethod,这就意味着ServiceMethod是属于函数的,而不是类的。也就是我们定义的网络访问接口类,在接口类里面的每一个函数都会在反射阶段形成自己的serviceMethod。那么ServiceMethod是什么呢?

ServiceMethod其实是用来存储一次网络请求的基本信息的,比如Host、URL、请求方法等,同时ServiceMethod还会存储用来适配OkHttpCall对象的CallAdpater。ServiceMethod的build方法会解读传入的Method,首先ServiceMethod会在CallAdpaterFactory列表中寻找合适的CallAdapter来包装OkHttpCall对象,这一步主要是根据 Method的返回参数来匹配的,比如如果方法的返回参数是Call对象,那么ServiceMethod就会使用默认的CallAdpaterFactory来生成CallAdpater,而如果返回对象是RxJava的Obserable对象,则会使用RxJavaCallAdapterFactory提供的CallAdpater。然后build方法会解读Method的注解,来获得注解上配置的网络请求信息,比如请求方法、URL、Header等。

  • 具体 ServiceMethod 讲解见下

3.3.2、okHttpCall 创建

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

我们知道,ServiceMethod封装了网络请求的基本信息,比如Host、URL等,我们根据ServiceMethod和请求参数args就可以确定本次网络请求的所有信息了,OkHttpCall主要是将这些信息封装起来,并调用OkHttp的接口去发送网络请求,这里,我们就将OkHttpCall看成是一个处理网络请求的类即可。

3.3.3、callAdapter 适配

在retrofit中,invoke() 里面的最后一行代码,

return serviceMethod.callAdapter.adapt(okHttpCall);
  • 那么我们可以设想一下为什么Retrofit还要设计一个CallAdapter接口呢?
    Retrofit真正使用Okhttp进行网络请求的就是OkHttpCall这个类

  • 如果没有这个适配器模式,会出现什么情况?
    很明显,没有适配器的时候此时我们网络请求的返回接口只能直接返回OkHttpCall,那么所有的网络请求都是用okhttpCall进行,这样的话就失去了retrofit 封装网络请求call的意义了,譬如:rxjavaCallAdapterFactory 就没有办法支持。

  • 适配器模式在此发挥了其应用的作用
    将网络请求的核心类OkHttpCall进行适配,你需要什么类型的数据就通过适配器适配,返回适配后的对象就是了。正是这种CallApdate接口的设计,使得我们在使用Retrofit的时候可以自定义我们想要的返回类型。此接口的设计也为RxJava的扩展使用做了很好的基础。

四、网络请求过程

4.1、请求很回调数据

我们以enqueue请求方式为例:(注意:使用的是默认配置)

        wifi.enqueue(new Callback<Object>() {
            @Override
            public void onResponse(Call<Object> call, Response<Object> response) {

            }

            @Override
            public void onFailure(Call<Object> call, Throwable t) {

            }
        });

然后执行ExecutorCallAdapterFactory#enqueue

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
      //此处使用静态代理,delegate 指的是:OkHttpCall
      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);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }
  • 注意:以上代码的delegate 是在此处传入的Retrofit#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, @Nullable Object[] args)
              throws Throwable {
            ...
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

然后再调用ExecutorCallAdapterFactory#CallAdapter#adapt方法:

  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        //创建 ExecutorCallbackCall 在里面执行网络请求
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

接着上面我们回到ExecutorCallAdapterFactory#enqueue在里面执行OkHttpCall#enqueue方法,在里面会创建 okhttpcall,执行网络请求。

  private @Nullable okhttp3.Call rawCall;

  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");

    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          //当 call 为空时,创建 call,此 call 为 okhttp.call
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }
    //执行 okhttp 请求
    call.enqueue(new okhttp3.Callback() {
      //请求成功
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          //解析数据 将okhttp 的 Response 转换成 retrofit 的 Response 
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }
      //请求失败
      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          // 成功失败 callback 回调到 ExecutorCallAdapterFactory 中的 代码块
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          // 成功执行 callback 回调到 ExecutorCallAdapterFactory 中的 代码块
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

执行OkHttpCall#createRawCall创建okhttp3.Call

  private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

4.2、回调数据格式转换,以 Gson 为例

OkHttpCall#enqueue#onResponse里面执行OkHttpCall#parseResponse方法:

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      rawBody.close();
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      //调用 serviceMethod 转换成数据转换器(converterFactories)里面对应的类型
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

执行ServiceMethod#toResponse方法

  R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

执行GsonResponseBodyConverter#convert方法装换成相应的Gson格式数据,再转换成相应的对象。

  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }

我们再看GsonConverterFactory中的请求和响应格式的转换。

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }

GsonRequestBodyConverter#convert 执行请求格式转换

  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public RequestBody convert(T value) throws IOException {
    Buffer buffer = new Buffer();
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
    JsonWriter jsonWriter = gson.newJsonWriter(writer);
    adapter.write(jsonWriter, value);
    jsonWriter.close();
    return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
  }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容