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类.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成功关键之一,因为适合多人同时开发。
- 一方只认识接口,想进入另一方,就披上那个接口外套吧。