Retrofit解析6之面向接口编程

整体Retrofit内容如下:

  • 1、Retrofit解析1之前哨站——理解RESTful
  • 2、Retrofit解析2之使用简介
  • 3、Retrofit解析3之反射
  • 4、Retrofit解析4之注解
  • 5、Retrofit解析5之代理设计模式
  • 6、Retrofit解析6之面向接口编程
  • 7、Retrofit解析7之相关类解析
  • 8、Retrofit解析8之核心解析——ServiceMethod及注解1
  • 9、Retrofit解析8之核心解析——ServiceMethod及注解2
  • 10、Retrofit解析9之流程解析
  • 11、Retrofit解析10之感谢

从本文开始,开始正式解析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解析6之面向接口编程_第1张图片
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.
 *
 * 

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 Successful response body type. */ public interface Call 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 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 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 clone(); /** The original HTTP request. */ Request request();

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

看下他的方法

Retrofit解析6之面向接口编程_第2张图片
方法.png

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

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

这里温馨提示下:

Request request();

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

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

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

三、CallAdapter接口

(一)、思考

同样两个问题?

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

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

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

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

第二个问题 我是这样想的

首先上面说了,既然是适配,肯定要有一个方法要去做适配把Retrofit的Call适配成业务方自定义的"Call"。其次,大家知道Retrofit的Call的泛型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 {
  /**
   * 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} is {@code Repo}. This type
   * is used to prepare the {@code call} passed to {@code #adapt}.
   * 

* 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}. *

* For example, given an instance for a hypothetical utility, {@code Async}, this instance would * return a new {@code Async} which invoked {@code call} when run. *


   * @Override
   * public  Async adapt(final Call call) {
   *   return Async.create(new Callable>() {
   *     @Override
   *     public Response call() throws Exception {
   *       return call.execute();
   *     }
   *   });
   * }
   * 
*/ T adapt(Call 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} 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} 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"。 此类型用于准备传递给"adapt"的"call"。 注意:这通常与提供给此呼叫适配器工厂的"returnType"不同。

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

T 就是代表Retrofit里面Call的一个实例。后面的我实在是翻译不好,对不起大家了,其实说白了就是讲一个Retrofit的Call 是适配成另外一个"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 ,则返回Runnable。(静态方法,有具体的实现)
  • static Class getRawType(Type type) 注释:提取type对应的原始类型。例如:List 则返回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.
 * 

* Callback methods are executed using the {@link Retrofit} callback executor. When none is * specified, the following defaults are used: *

    *
  • Android: Callbacks are executed on the application's main (UI) thread.
  • *
  • JVM: Callbacks are executed on the background thread which performed the request.
  • *
* * @param Successful response body type. */ public interface Callback { /** * Invoked for a received HTTP response. *

* 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 call, Response 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 call, Throwable t);

1、先看下 的注释

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

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

  • 1、void onResponse(Call call, Response response) 注释:调用接收的HTTP响应。注意:HTTP响应可能是指示应用程序级别的故障,例如404或500。调用 Response的isSuccessful()方法来判断响应是否成功。
  • 2、void onFailure(Call 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 {
  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}
     * declaration.
     */
    public Converter 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 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 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 responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) 注释:返回一个处理HTTP 响应的的body的Converter(转换器),转入类型ResponseBody,如果因为type(类型)无法处理,工厂无法处理,则返回null。例如:一个Retrofit的Call是Call,则对应的响应body的类型应该是 SimpleResponse。
  • 2、Converter requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) 注释:返回一个可以处理将HTTP的请求(resquest)中的body的Converter对象,转出类型是RequestBody。如果因为type(类型)无法处理,则返回null。这个Converter主要是为了处理@Body 注解,@Part 注解,@PartMap的类型转换。
  • 3、Converter 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>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call adapt(Call call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

  static final class ExecutorCallbackCall implements Call {
    final Executor callbackExecutor;
    final Call delegate;

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

    @Override public void enqueue(final Callback callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      delegate.enqueue(new Callback() {
        @Override public void onResponse(Call call, final Response 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 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 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 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 adapt(Call call) 方法返回的是 new的一个ExecutorCallbackCall对象。

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

    (二)、ExecutorCallbackCall类分析

    1、上源码
    static final class ExecutorCallbackCall implements Call {
        final Executor callbackExecutor;
        final Call delegate;
    
        ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
          this.callbackExecutor = callbackExecutor;
          this.delegate = delegate;
        }
    
        @Override public void enqueue(final Callback callback) {
          if (callback == null) throw new NullPointerException("callback == null");
    
          delegate.enqueue(new Callback() {
            @Override public void onResponse(Call call, final Response 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 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 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 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 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。大家不要混淆了!

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

    九、面向接口编程

    Retrofit解析6之面向接口编程_第3张图片
    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成功关键之一,因为适合多人同时开发。
    • 一方只认识接口,想进入另一方,就披上那个接口外套吧。

    你可能感兴趣的:(Retrofit解析6之面向接口编程)