Retrofit解析6之面向接口编程

整体Retrofit内容如下:

从本文开始,开始正式解析Retrofit源码,本文的结构如下:

1、解析思路
2、Call接口
3、CallAdapter接口
4、Callback接口
5、Converter接口
6、ExecutorCallAdapterFactory类
7、Platform类
8、HttpException类
9、面向接口编程

一、解析思路:

(一)、假设

在讲解,解析思路之前,我们先想一下,那么想什么那?如果让你"设计"一个类似Retrofit的库,你要怎么"设计"那?
注意是重点是 "设计" ,不是 "写"
那怎么 "设计" 那?那我先说我的思路,如果是我,我先想摸清需求
需求如下:

  • 1、首先要解耦,请求和构建请求分离,所以必须在这里"库"里面组建一个Call来和okHttp里面的Call对应
  • 2、有返回值的时候给外部调用的回调。
  • 3、如果需要把响应内部的响应体
  • 4、支持响应体自动反序列化。

所以如果我让我设计这么一个库,必须先写三个接口,每个接口对应上面的一个问题。这里我们又想到一个Call和转换,是两个需求,根据单一原则,应该是四个接口
分别是:

  • 1、一个接口表征一个HTTP请求
  • 2、一个类型转化接口,负责本地库的HTTP请求与其他类型的转化,比如转化为RxJava,既然请求可以转化,那么响应的返回值转化也应该在这里做。
  • 3、序列化与反序列化操作
  • 4、响应回调的处理
所以我在设计的时候,肯定要设计这四个接口,然后在围绕这四个接口进行操作,这是我的设计思想,那你们的那?

下面看下他的类目录结构


Retrofit类.png

如上图所示,有4个接口

  • Call接口
  • CallAdapter接口
  • Callback接口
  • Converter接口
    这四个接口是不是刚好对上我的那个四个接口。如果大家对面向接口编程不是很熟悉,没关系,在本篇文章的最后一部分,我单独给大家讲解下,我所理解的相面接口编程。那么我们先来看下这几个接口。

二、Call接口

(一)、思考

两个问题:

  • 1、在看这个这接口的时候,大家想下,Retrofit为什么要创建这个接口,并且命名为Call,先思考5分钟。再看下面的内容。
  • 2、如果让你"设计"这个Call接口你要怎么设计

————————分割线,思考上面的问题——————————

不知道你们的想法,不过我先说下我的想法

第一个问题 我是这么想的

这个Call 肯定模拟了一个客户端发起请求到服务器,然后服务器响应数据到客户端的整个流程。通过这个Call我们可以获取相应的请求和相应的信息。

第二个问题 我是这样想的

既然是模拟了整个请求和响应逻辑,所以肯定要设计一个发起请求的方法,来模拟发请求;既然是请求,所以必然包含一个同步请求的方法,表征同步请求,设计一个异步请求的方法,表征一个异步请求;还要设计一个取消请求的的方法,表征一个取消请求的方法。我能想到就是这么多了,你们的那?

OK,那我们来看下这个接口的源码看下Retrofit是怎么设计的。

(二)、来看下接口的源码

/**
 * An invocation of a Retrofit method that sends a request to a webserver and returns a response.
 * Each call yields its own HTTP request and response pair. Use {@link #clone} to make multiple
 * calls with the same parameters to the same webserver; this may be used to implement polling or
 * to retry a failed call.
 *
 * <p>Calls may be executed synchronously with {@link #execute}, or asynchronously with {@link
 * #enqueue}. In either case the call can be canceled at any time with {@link #cancel}. A call that
 * is busy writing its request or reading its response may receive a {@link IOException}; this is
 * working as designed.
 *
 * @param <T> Successful response body type.
 */
public interface Call<T> extends Cloneable {
  /**
   * Synchronously send the request and return its response.
   *
   * @throws IOException if a problem occurred talking to the server.
   * @throws RuntimeException (and subclasses) if an unexpected error occurs creating the request
   * or decoding the response.
   */
  Response<T> execute() throws IOException;

  /**
   * Asynchronously send the request and notify {@code callback} of its response or if an error
   * occurred talking to the server, creating the request, or processing the response.
   */
  void enqueue(Callback<T> callback);

  /**
   * Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain
   * #enqueue(Callback) enqueued}. It is an error to execute or enqueue a call more than once.
   */
  boolean isExecuted();

  /**
   * Cancel this call. An attempt will be made to cancel in-flight calls, and if the call has not
   * yet been executed it never will be.
   */
  void cancel();

  /** True if {@link #cancel()} was called. */
  boolean isCanceled();

  /**
   * Create a new, identical call to this one which can be enqueued or executed even if this call
   * has already been.
   */
  Call<T> clone();

  /** The original HTTP request. */
  Request request();

老规矩先看下类的注释
我简单的翻译一下:
通过调用Retrofit的方法向web服务器发送请求并返回响应。每一次调用都产生自己的HTTP请求和对应的响应 对儿。如果出现了在避免轮询或者失败重试的情况,可以 调用clone()方法 复制 可以对具有相同的web服务器进行 具有相同参数的 请求。
同步调用 采用execute方法,异步采用enqueue方法,在任何情况下, 一个请求Call 都有可以通过cancel取消,一个Call在写入请求或读取响应的时候是可能产生IOExcetption的,这是再正常不过的了。
参数<T> 是成功的响应体类型

看下他的方法

方法.png

和大家设计的一样吗?我是少了三个方法,分别是

  • boolean isExecuted(); 判断是否正在运行中
  • sCanceled(); 判断是否已经取消了
  • Call<T> clone(); 复制一个连接,为了轮训和请求失败的时候用

这里温馨提示下:

Request request();

里面的返回值是okhttp3.Request。这里返回是okHttp的request。大家怎么看这个情况,我的理解是在接口层面指定了okHttp的request,则指明了底层的请求只能使用okHttp了

PS:大家注意一下这个接口和okhttp3.Call的接口基本上一致,只不过多了一个clone()方法。

这个接口,目前就研究结束了,不知道大家怎么看待这个接口,希望大家看完这个接口的介绍,心里对Call这个接口有一个比较深刻的认识

三、CallAdapter接口

(一)、思考

同样两个问题?

  • 1、retrofit为什么要设计这个类?
  • 2、如果让我们设计,我们怎么设计这个接口

————————分割线,思考上面的问题——————————

不知道你们的想法,不过我先说下我的想法
第一个问题 我是这么想的

我们知道retrofit是支持RxJava的,那么如果一个RxJava是需要转化成一个Retrofit中的Call<T>,那肯定需要一个适配器,把一个RxJava的Observable适配成一个Retrofit的Call<T>,所以设计这个类的主要目的就是适配让Retrofit的Call<T>对业务层的请求适配,这样整个结构更清晰。

第二个问题 我是这样想的

首先上面说了,既然是适配,肯定要有一个方法要去做适配把Retrofit的Call<T>适配成业务方自定义的"Call"。其次,大家知道Retrofit的Call<T>的泛型T是response的Body,这个类型是泛型,所以最后反序列化的时候需要反序列化成一个对象,这个需要指定这个对象的类型,所以还应该获取这个类的具体"类型"。

这是我之前的想法,大家的想法如何?那我们来仔细看一下他的源代码

(二)、读源码

/**
 * Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
 * created by {@linkplain Factory a factory} which is
 * {@linkplain Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit}
 * instance.
 */
public interface CallAdapter<R, T> {
  /**
   * Returns the value type that this adapter uses when converting the HTTP response body to a Java
   * object. For example, the response type for {@code Call<Repo>} is {@code Repo}. This type
   * is used to prepare the {@code call} passed to {@code #adapt}.
   * <p>
   * Note: This is typically not the same type as the {@code returnType} provided to this call
   * adapter's factory.
   */
  Type responseType();

  /**
   * Returns an instance of {@code T} which delegates to {@code call}.
   * <p>
   * For example, given an instance for a hypothetical utility, {@code Async}, this instance would
   * return a new {@code Async<R>} which invoked {@code call} when run.
   * <pre><code>
   * @Override
   * public <R> Async<R> adapt(final Call<R> call) {
   *   return Async.create(new Callable<Response<R>>() {
   *     @Override
   *     public Response<R> call() throws Exception {
   *       return call.execute();
   *     }
   *   });
   * }
   * </code></pre>
   */
  T adapt(Call<R> call);

  /**
   * Creates {@link CallAdapter} instances based on the return type of {@linkplain
   * Retrofit#create(Class) the service interface} methods.
   */
  abstract class Factory {
    /**
     * Returns a call adapter for interface methods that return {@code returnType}, or null if it
     * cannot be handled by this factory.
     */
    public abstract CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);

    /**
     * Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
     * example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    /**
     * Extract the raw class type from {@code type}. For example, the type representing
     * {@code List<? extends Runnable>} returns {@code List.class}.
     */
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}
1、老规矩先来看下 的注释:

将一个Call和他的响应类型R适配成T类型。实例由对应的Factory来创建,这个对应的Factory是通过Retrofit.Builder的addCallAdapterFactory(Factory)方法添加到Retrofit对象中的,在上述的过程中实现的初始化。

再来看下他两个方法的注释

2、看下他的Type responseType()方法的注释

返回此适配器将HTTP响应body转换为Java对象时使用的类型。 例如,"Call <Repo>"的响应类型是"Repo"。 此类型用于准备传递给"adapt"的"call"。 注意:这通常与提供给此呼叫适配器工厂的"returnType"不同。

3、看下他的 T adapt(Call<R> call)方法的注释

T 就是代表Retrofit里面Call的一个实例。后面的我实在是翻译不好,对不起大家了,其实说白了就是讲一个Retrofit的Call<T> 是适配成另外一个"Call"

4、看下他的子类 abstract class Factory

看上面的源码大家知道Factory是个子类,一般用Factory都是工厂模式。
老规矩看下他的 ***类**** 的注释,翻译一下就是

基于Retrofit的create方法的返回值创建CallAdapter实例。

看完上面的注释,大家应该发现了Retrofit的一个规律就是:retrofit定义了CallAdapter接口,内部有定义了一个Factory,工厂方法定义了如何生成CallAdapter,而CallAdapter又定义了如何拿到业务层定义的"Call"。所以他们的顺序如下:CallAdapter.Factory——>CallAdapter——>自定义的"Call"。

再来看下他的几个方法

  • public abstract CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) 的注释:返回一个CallAdapter的实例,如果工厂无法处理则返回null。(注意:抽象的方法,需要子类去实现的)
  • Type getParameterUpperBound(int index, ParameterizedType type) 注释:
    已知指定位置(index) 对应的类型(type) 来获取泛型中的通配符的参数的上线,例如:Map <String,? 扩展Runnable>,则返回Runnable。(静态方法,有具体的实现)
  • static Class<?> getRawType(Type type) 注释:提取type对应的原始类型。例如:List<? extends Runnable> 则返回List.class

四、Callback接口

这个接口就比较简单了,就不用大家思考了,Callback看字面意思就是回调,里面肯定一个是成功的回调,一个是错误的回调。直接读下源码

/**
 * Communicates responses from a server or offline requests. One and only one method will be
 * invoked in response to a given request.
 * <p>
 * Callback methods are executed using the {@link Retrofit} callback executor. When none is
 * specified, the following defaults are used:
 * <ul>
 * <li>Android: Callbacks are executed on the application's main (UI) thread.</li>
 * <li>JVM: Callbacks are executed on the background thread which performed the request.</li>
 * </ul>
 *
 * @param <T> Successful response body type.
 */
public interface Callback<T> {
  /**
   * Invoked for a received HTTP response.
   * <p>
   * Note: An HTTP response may still indicate an application-level failure such as a 404 or 500.
   * Call {@link Response#isSuccessful()} to determine if the response indicates success.
   */
  void onResponse(Call<T> call, Response<T> response);

  /**
   * Invoked when a network exception occurred talking to the server or when an unexpected
   * exception occurred creating the request or processing the response.
   */
  void onFailure(Call<T> call, Throwable t);
1、先看下 的注释

从服务器或离线请求的对应的响应(response)。 对应指定请求的,有且仅有一个方法与其对应。
由Retrofit的callback executor执行回调方法。当没有指定时,使用下面的默认值:
如果是 Android:回调在应用程序的主(UI)线程上执行,如果是JVM,则在执行请求的后台线程上执行回调。
泛型参数<T> 代表成功的响应类的类型

这个接口就两个方法,一个对应成功的回调,一个对应失败的回调

  • 1、void onResponse(Call<T> call, Response<T> response) 注释:调用接收的HTTP响应。注意:HTTP响应可能是指示应用程序级别的故障,例如404或500。调用 Response的isSuccessful()方法来判断响应是否成功。
  • 2、void onFailure(Call<T> call, Throwable t) :注释:当与服务器交互时、当创建请求、当处理响应时产生Exception 均调动该方法。

五、Converter接口

Converter我认为挺简单的,就是负责类型转换

(一)、思考

一个问题:

1、如果让你"设计"这个Converter接口你要怎么设计
————————分割线,思考上面的问题——————————
这个问题 我是这么想的

因为是给网络场景下的使用的,我的第一反应是写两个方法,一个方法是在请求的时候,写数据进行序列化的时候;还有一个就是在响应的时候, 读取数据进行反序列化的时候。

(二)、源码

/**
 * Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
 * Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
 * into the {@link Retrofit} instance.
 */
public interface Converter<F, T> {
  T convert(F value) throws IOException;

  /** Creates {@link Converter} instances based on a type and target usage. */
  abstract class Factory {
    /**
     * Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for
     * response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
     * declaration.
     */
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
        Retrofit retrofit) {
      return null;
    }

    /**
     * Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
     * values.
     */
    public Converter<?, RequestBody> requestBodyConverter(Type type,
        Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
      return null;
    }

    /**
     * Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Field @Field}, {@link FieldMap @FieldMap} values,
     * {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
     * {@link Query @Query}, and {@link QueryMap @QueryMap} values.
     */
    public Converter<?, String> stringConverter(Type type, Annotation[] annotations,
        Retrofit retrofit) {
      return null;
    }
  }
}
1、看下类的注释

在HTTP请求中实现对象的转化。Converter这个类的实例由Factory创建。而这个Factory则由Retrofit.Builder的addConverterFactory()方法来进行初始化的

这个接口的抽象方法比较少,就一个

T convert(F value) throws IOException

不用注释,大家也知道把F 转化为T,这个接口是有两个参数的,我把F称为转入类型,T为转出类型,因为要把F转化为T。

哎 好像和我想象的不一样哎,那我们继续看下他的抽象类Factory

2、抽象类Factory

看名字就知道是个工厂类,肯定是通过这个工厂来产生Converter对象。

(1)、看下类的注释

基于类型和目标来创建一个Converter的实例

(2)、看下对应的三个方法的注释
  • 1、public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) 注释:返回一个处理HTTP 响应的的body的Converter(转换器),转入类型ResponseBody,如果因为type(类型)无法处理,工厂无法处理,则返回null。例如:一个Retrofit的Call是Call<SimpleResponse>,则对应的响应body的类型应该是 SimpleResponse。
  • 2、Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) 注释:返回一个可以处理将HTTP的请求(resquest)中的body的Converter对象,转出类型是RequestBody。如果因为type(类型)无法处理,则返回null。这个Converter主要是为了处理@Body 注解,@Part 注解,@PartMap的类型转换。
  • 3、Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) 注释:支持返回一个转出类型为String的Converter实例。如果类型不能处理,则返回null。这个主要是为了 @Field,FieldMap,@FieldMap , @Header, @HeaderMap, @Path, @Query, @QueryMap 这些注解创建的 @Converter转换器
(3)、总结

Retrofit 明显想的比我多,设计比我优雅,那我们来总结下这个接口

  • 1、Converter 这个类的职责主要是做** 类型转化 **,Retrofit定义了Converter,但是接口内部有个内部类负责创建Converter。
  • 2、大家注意到没Factory虽然是个抽象类,但是他的三个方法都不是抽象方法。
  • 3、Factory的三个方法目的不一样,都的是真针对请求体,有的针对响应体。

六、ExecutorCallAdapterFactory

上文讲解Platform中的静态内部类Android的defaultCallAdapterFactory方法里面返回的是一个ExecutorCallAdapterFactory的对象。那我们就在讲解下ExecutorCallAdapterFactory类

(一)、上源码

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

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }
  // get方法,创建并返回Android平台默认CallAdapter
  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
     //先判断原始类型是不是Call,这个Call是retrofit包下的Call
    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) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

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

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(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();
    }
  }
}

麻蛋,又是一个没有注释的类,不过通过源码我们知道这是一个final类,不能被继承。

首先这个ExecutorCallAdapterFactory类实现了CallAdapter.Factory,所以必然实现了CallAdapter.Factory接口的方法,我们来看下这个get方法内部的实现流程

  • 1、首先判断原始类型
  • 2、通过调用Utils.getCallResponseType()获取** "响应" **(不是"相应")的类型。
  • 3、new了一个CallAdapter的匿名内部类,注意这个CallAdapter的两个泛型分别是Object和Call<?>,这个CallAdapter的两个抽象方法的实现:(1)、Type responseType返回的是第2步产生的"响应"类型;(2)、Call<Object> adapt(Call<Object> call) 方法返回的是 new的一个ExecutorCallbackCall对象。

ExecutorCallbackCall是个神马东西,原来ExecutorCallbackCall是ExecutorCallAdapterFactory的静态内部类,那么我们来分析一下ExecutorCallAdapterFactory类。

(二)、ExecutorCallbackCall类分析

1、上源码
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);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(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();
    }
  }
2、看上面源码我们能得知如下内容:
  • 1、ExecutorCallbackCall实现了Retrofit里面的Call接口,所以ExecutorCallbackCall是Retrofit里面的Call的实现类,所以必然实现了对应Call的抽象类。
  • 2、如果想要构造一个ExecutorCallbackCall对象,必须传入一个Executor和Call两个对象才行。
  • 3、无论是发起同步请求还是异步请求,或者取消请求,其实真正的操作对象是,构造时传入的delegate。
  • 4、无论同步,还是异步,调用的线程池都是 ,构造时传入的callbackExecutor,而在Android那部分我们知道callbackExecutor其实就是MainThreadExecutor,所以最后无论同步还是异步,最后都会切换到UI主线程中去
3、所以总结一下ExecutorCallbackCall类

它实现了Call这个接口,Call我们前面说了,就是一个网络请求,然而我们这里看到这里并没有做实际请求,而是用了一个静态代理,通过这个delegate代理来实现call的请求,而在这里面做了一些其他的逻辑比如cancel逻辑,而实际上做这个请求还是交给了delegate。(其实OkHttpCall)

(三) ExecutorCallAdapterFactory 类总结

ExecutorCallAdapterFactory是CallAdapter.Factory的实现类,ExecutorCallAdapterFactory是将Call 适配成Call接口。但适配前和适配后的Call 还是不一样的,从enqueue方法中可以看到在callbackExecutor执行了回调,callbackExecutor上文已经介绍了,在Android平台就是UI主线程。

七、Platform类

为了方便大家后期更好的理解源码,我先给大家介绍一下Platform。这个Platform是个神马东东,字面理解是"平台",有啥神功疗效?
工欲善其事必先利其器,我们先来看下源码

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

  Executor defaultCallbackExecutor() {
    return null;
  }

  CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

  boolean isDefaultMethod(Method method) {
    return false;
  }

  Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args)
      throws Throwable {
    throw new UnsupportedOperationException();
  }

  @IgnoreJRERequirement // Only classloaded and used on Java 8.
  static class Java8 extends Platform {
    @Override boolean isDefaultMethod(Method method) {
      return method.isDefault();
    }

    @Override Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
        Object... args) throws Throwable {
      // Because the service interface might not be public, we need to use a MethodHandle lookup
      // that ignores the visibility of the declaringClass.
      Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
      constructor.setAccessible(true);
      return constructor.newInstance(declaringClass, -1 /* trusted */)
          .unreflectSpecial(method, declaringClass)
          .bindTo(object)
          .invokeWithArguments(args);
    }
  }

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

这个类好坑啊,居然没有注释,不过通知字面的意思,我们

(一)、初始化

Platform 的初始化

  private static final Platform PLATFORM = findPlatform();
  static Platform get() {
    return PLATFORM;
  }
  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

Platform字面的意思就是平台。所以Platform其实就是一个父类,不同平台对应不同的实现子类。Android、Java 8 对应的是各种具体平台。可以看到,调用findPlatform()方法之后就回去判断对应的平台,具体实现的子类就是Android 和Java。

这里提一下我的小插曲,按照我之前分析okHttp的思路,okHttp里面也有Platform。所以我直接在Retrofit的包下找AndroidPlatform,结果发现没有,我就蒙圈了,后来才发现在Platform的内部类里面,汗.....

由于我们针对Android平台关于Java的具体设置,我就不讲解了,这里看下对应的Platform的内部类Anroid

(二)、Android

Android是Platform的静态内部类
代码很简介,如下:

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
  }

而Android类就两个方法,一个是defaultCallbackExecutor,另外一个是defaultCallAdapterFactory,从字面的意思我们可以知道,defaultCallbackExecutor()这个方法应该是返回的是默认的回调的线程池容器,defaultCallAdapterFactory()方法返回的是默认的请求适配工厂(CallAdapterFactory)。

那MainThreadExecutor是什么东西?原来MainThreadExecutor是Android的静态内部类。那我们来看下MainThreadExecutor这个类

(三)、MainThreadExecutor

看字面意思,我的理解是主线程的线程池。
来看下源码:

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }

代码很简单,通过new Handler(Looper.getMainLooper())来获取一个主线程的Handler。然后在执行主线程的时候,调用的是主线程的handler的post方法。

ExecutorCallAdapterFactory 这个类 我们在下面讲解。

(四)、总结

Platform 其实就是一个"平台",定义了一些平台共有的方法,然后也针对不同的平台定义了一些不同的具体实现子类,比如各个不同平台根据不同环境来初始化不同的MainThreadExecutor。这里也可以看到,在初始化Platform之后,通过Platform得到的ExecutorCallAdapterFactory的工厂的Excecutor其实就是运行在主线程的Executor。

八 HttpException类

这个类比较简单,就不用想了,肯定肯定是Retrofit处理异常的的异常包装类,代码不多,直接上源码:

/** Exception for an unexpected, non-2xx HTTP response. */
public class HttpException extends Exception {
  private static String getMessage(Response<?> response) {
    if (response == null) throw new NullPointerException("response == null");
    return "HTTP " + response.code() + " " + response.message();
  }

  private final int code;
  private final String message;
  private final transient Response<?> response;

  public HttpException(Response<?> response) {
    super(getMessage(response));
    this.code = response.code();
    this.message = response.message();
    this.response = response;
  }

  /** HTTP status code. */
  public int code() {
    return code;
  }

  /** HTTP status message. */
  public String message() {
    return message;
  }

  /**
   * The full HTTP response. This may be null if the exception was serialized.
   */
  public Response<?> response() {
    return response;
  }
}

通过注释我们知道,这个HttpException主要是用来处理意外的、非2xx的响应异常
这个类就三个变量

  • int code :http的状态code,比如:405、501等
  • String message : http状态的信息
  • Response<?> response : 服务器的响应
    这个三个参数在构造函数里面进行初始化的,由于这三个变量分别是private,所以必然有一个对应的get方法。不过这里的方法并没有以"get"开头。

最后他又定义了 静态方法getMessage(Response<?>),传入一个Response,返回一个拼接的String。

PS:

HttpException 里面的Response是Retrofit里面的Response,OkHttp里面也有一个Response。大家不要混淆了!

这个类比较简单,只能讲这么多了

九、面向接口编程

oop.png

面向接口编程

Interface-based programming, also known as interface-based architecture, is an architectural pattern for implementing modular programming at the component level in an object-oriented programming language which does not have a module system.

翻译一下:

面向接口编程,也被熟知为基于接口的设计,是一种基于组件级别的,面向对象语言的模块化编程设计实现。

说道面向接口不得不说面向对象,不过面向接口编程和面向对象编程实际上两个不同层级的概念。理论上说具有对象概念的程序设计都可以称之为面向对象编程,而面向接口编程则是从组件的级别来设计代码,认为地将抽象与实现分离。面向接口编程仅仅是面向对象编程的一种模块化实现形式而已。

(一)所谓的“接口”

面向接口编程中的"接口" 二字具体到Java语言中不仅仅是"interface"关键字这么简单。可以理解为接口是对具体实现的抽象。试想一下,团队协同以及代码健壮可维护性的需求日益增强的趋势下,通过暴露接口来提供服务本身是一件非常愉悦的事情。A需要调用B的服务,A却不需要去仔细阅读B写的代码,通过接口文档就可以看出对应业务的方法和参数类型,进而使用RMI或者RPC等相关技术实现模块化的调用。而这一切本身就是相面接口编程。

换一种角度,我们怎么定义接口:“接口泛指实体把自己提供给外界的一种抽象化物,用以由内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的方式”,话句话说,在我们程序的世界里,接口的作用就是用于定义一个或一组规则,实现对应接口的实体需要遵循对应的这些规则。也可以说是对“同类事物”的抽象表示,而“同类事物”的界定就看是否实现了同一个接口,譬如一个Animal接口和NightWorking接口,公鸡实现了Animal接口,猫头鹰实现了Animal接口和NightWorking接口,还有一个实现了NightWorking的接口的酒吧,在Animal的范畴下,我们可以称公鸡和猫头鹰是同类事物,但是在NightWorking的范畴下,我们可以把我们可以称猫头鹰和酒吧是同类事物。有点恐怖吧

很多刚刚接触面向接口编程的Java开发者会认为,既然面向接口编程,那么就把实现抽象为接口就是优良的设计。但实际上他们混淆了Java中的interface和面向接口编程的"接口的"概念。实际上,interface、abstract class以及普通的class 都能成为所谓的接口,甚至 abstract class的功能可以更加强大。那么interface和abstract class 区别是什么?

(二)、abstract class和interface的区别:

abstract class和interface的区别在于,interface约定的是务必实现的方法,强调的是规则的制定。abstract class则是在抽象的同时允许提供一些默认的行为,以达到代码复用的效果。例如一定一些基础、初始化以及类回收方法等。另外,还有一个常识性的区别,一个实现类(相对于抽象而言)可以实现多个interface,而只能继承一个abstract class,在代码设计的过程中务必注意。

(三)、面向接口的优势:

  • 1、方便程序使用多态
    例如有方法需要一个集合类型的参数,将参数设置为List类型和设置成ArrayList相比,入惨不仅可以传入ArrayList类型还可以是LinkedList类型,因此代码使用范围更广。
  • 2、代码扩展性更强
    如果要扩展一个类的方法,我们一般可以选择动态代理方式来对某些方法进行增强,但是动态代理的类需要实现接口,这也是面试接口编程的一大优势。
  • 3、降低了代码间的耦合
    例如:计算机Computer类有一个IStrorage接口类型和成员变量,接口定义了write和read方法,移动设备类FlashDisk,MP3类实现了IStrorage接口,那么计算Computer类和FlashDisk、MP3就能关联成功,但是Computer并不知道自己的成员变量是什么具体类型,这就是所有的"依赖几口,而不依赖具体类"。Java中两个层面之间通过接口产生联系,此时接口相当于一个缓冲区,当业务发生改变,只改变实现类的代码即可,必须要改写后续代码,减少对整个系统的影响。

(四)、 面向接口的编程方式

  • "定义接口"——"定义类": 先定义接口,再实现类
  • 任何需要在函数间传入传出的一定是接口而不是具体的类,面向接口的编程方式是Java成功关键之一,因为适合多人同时开发。
  • 一方只认识接口,想进入另一方,就披上那个接口外套吧。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容