本文转载至:http://www.apkbus.com/blog-705730-60159.html
Retrofit 是 Github 上面 squre 组织开发的一个类型安全的 Http 客户端,它可以在 Java 和 Android 上面使用。Retrofit 将描述请求的接口转换为对象,然后再由该对象去请求后台。Retrofit 将请求对象化了。目前已经发布了 2.0beta 版本。
Retrofit 主要有以下功能特点
这是一个简单的例子,访问httpbin网站。也可以看完整的Retrofit Demo 首先声明一个 java 接口
public interface HttpbinService {
@GET("/get?arg1=hello")
Call<HttpbinRequest> testGet();
}
使用方式
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://httpbin.org")
.addConverterFactory(GsonConverterFactory.create())
.build();
HttpbinService httpbinService = retrofit.create(HttpbinService.class);
使用 httpbinService 获取一个 Call,用来请求 HTTP 服务器。
Call<HttpbinRequest> call = httpbinService.testGet();
因为接口返回的应该是一个 Call,用来请求后台 HTPP 服务器,所以我们在声明接口的似乎,返回参数应该是 Call<?>。由于 httpbin 返回的是一个 json 格式的数据,我们想要返回直接的自定义的模型数据,但是 retrofit 默认只会返回 ResponseBody,所以我们需要自己添加一个 GsonConverter 第三方库。在 build.graddle 中的 dependencies 添加:
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
Retrofit 可以分为注解解析(Request 生成),请求执行,请求回调(异步处理),响应体转化几个部分。其中请求执行与请求回调可以算作一个部分,并且请求回调也可以没有,Call 有直接执行的接口 execute。
这里面第三部与第四步是可以合在一起的,但是目前 Retrofit 提供的默认代码中,会通过 Call,加入 Callback,用户可以在 Callback 中处理结果。
注解(Annotation)是 Retrofit 预先定义的注解,包括 Http 的各个部分,比如 POST、GET、Query、QueryMap、Field 等等。
其中生成 Call 的部分可以看下面关于这个适配器的类图。
首先是整个项目的类图
对于 Retrofit 项目中 CallAdapter 用着适配器模式也挺巧的,通过适配器将 Callback 回调接口运行在 UI 线程。下面时有关 CallAdapter,Call,Callback 的类图,其中也是连续用了两次代理模式。
ExecutorCallback 代理的是用户自定义的 Callback。通过这种方式让 OkHttpCall 去执行 Call,让 ExecutorCallback 将用户自定义的 Callback 运行在指定线程上。
在 Retrofit 开源库中,Retrofit 类是用户最基础的访问入口。然后 Converter 部分是由用户自己扩展的,而 Paraser 部分的相关类 RequestBuilder,RequestFactory 等则主要是负责解析接口并且生成 Request,而 Call,CallAdapter 等主要是负责底层的 Http 请求,以及请求后线程转换。
Retrofit 类是包含了一个构造器 Retrofit.Builder,由 Builder 指定 Retrofit 的相关参数,创建一个新的 Retrofit。Retrofit 中包含了很多重要的成员变量,而这些成员变量都是可以自设置的。
Retrofit 包含以下成员变量:
OkHttpClient()
。Retrofit 重要方法:
如果没有找到对应的 CallAdapterFactories,得到 CallAdapter,则该方法会抛出一个 IllegalArgumentException 异常,异常里面的 message 会是"Could not locate call adapter for ",如果遇到这个异常,则去判断对应的方法的返回类型是不是与 CallAdapterFactory 不匹配。
MethodHandler 是 retrofit 中连接了解析部分,执行部分,转换部分的一个关键的中间类。不过 MethodHandler 的代码量很少。它可以说是连接各个部分的桥梁,也是接口方法的描述类。它有包含了 retrofit,requestFactory,callAdapter,responseConverter 成员变量。主要方法如下
Object invoke(Object... args) {
return callAdapter.adapt(new OkHttpCall<>(retrofit, requestFactory, responseConverter, args));
}
这两个类别都是在 Converter 文件下。Converter 是接口,Factory 抽象类,很简短。
public interface Converter<F, T> {
T convert(F value) throws IOException;
abstract class Factory {
// 返回将 ResponseBody 转化为 Type 具体的对象的 Converter
public Converter<ResponseBody, ?> fromResponseBody(Type type, Annotation[] annotations) {
return null;
}
//返回将函数 Body 参数转化为 RequestBody 的 Converter
public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) {
return null;
}
}
}
Factory 主要是负责生成两种 Converter。Retrofit 实现了一个简单的 BuiltInConverters。
这是 Retrofit 的框架基础接口。它是 Retrofit 的发送请求给服务器并且返回响应体的调用。每个 Call 都有自己的 HTTP 请求和相匹配的响应。 它有如下四个接口:
Response<T> execute() throws IOException;
void enqueue(Callback<T> callback);
void cancel();
Call<T> clone();
这是 Retrofit 的框架基础接口。CallAdapter 是将一个 Call 适配给另外一个 Call 的适配器接口。它有以下两个接口:
Type responseType();
<R> T adapt(Call<R> call);
请求结构的回调接口。在 Call 的 enquene 接口中使用 有如下两个方法
void onResponse(Response<T> response, Retrofit retrofit);
void onFailure(Throwable t);
实现了 Call 接口,但同样是模版类。首先介绍一下 OkHttpCall 的主要函数:
private com.squareup.okhttp.Call createRawCall()
根据由 requestFactory 根据 args 创建一个 Request,然后利用这个 Request 创建一个 okhttp.Call。
private Response<T> parseResponse(com.squareup.okhttp.Response rawResponse) throws IOException
解析 okhttp.Response, 1. 首先将 body 读取出来作为 rawBody,然后用 OkHttpCall.NoContentResponseBody 作为新的 Body,创建新的 rawResponse。 2. 判断 Response.code(),如果不在 200 范围内,读取 rawBody 出来,返回一个错误的 retrofit 的 Response。如果 code 为 204 或 205(没有返回内容),则返回一个 body 为空的 retrofit 的 Response。 3. 如果 code 正常,则用 OkHttpCall.ExceptionCatchingRequestBody 包装一下 rawBody, 然后使用 responseConverter 将包装后的 catchingBody 转化为具体的返回类型数据。
OkHttpCall 是将 Request 放入到 okhttp 的 Call 里面执行,执行完成后,又将 okhttp 的 Call 返回的 Response 转化为 retrofit 的 Response,在此同时将 Body 里面的内容,通过 converter 转化为对应的对象。这个 OkHttpCall
这个类是包含了具体返回对象的响应体。里面包含了模版参数 T 类型的 body 对象,以及 okhttp 的 Response。
在 Retrofit 里面创建了 Body 注解,Filed 注解(Field,FieldMap),请求方法注解(DELETE,GET,PATCH,POST,PUT),请求头注解(HEAD,Header,Headers),multipart 注解(Part,Multipart,PartMap),接口加码(FormUrlEncoded),Url,Streaming,查询(Query,QueryMap),参数路径(Path),HTTP
这是一个抽象类,只有一个未实现的 perform 方法。
abstract void perform(RequestBuilder builder, Object value);
但是在 RequestBuilderAction 类里面有很多 RequestBuilderAction 的子类,分别对应注解类。Url,Header,Path,Query,QueryMap,Field,FieldMap,Part,PartMap,Body 都是在 RequestBuilderAction 的内部类,并且继承了 RequestBuilderAction。RequestBuilder 就是将对应注解的值给 RequestBuilder。
这是一个 okhttp.Request 的创建类。负责设置 HTTP 请求的相关信息,创建 Request。它主要有以下方法:
它的构造方法如下: RequestBuilder(String method, HttpUrl baseUrl, String relativeUrl, Headers headers, MediaType contentType, boolean hasBody, boolean isFormEncoded, boolean isMultipart)
RequestBuilder 就是创建请求。
RequestFactory 是创建 Request,他有个 create 方法,
Request create(Object... args) {
参数是接口函数对应的参数值,cerate 是创建 RequestBuilder,遍历 RequestFactory 的成员变量 requestBuilderActions,设置好 RequestBuilder,最后创建 Request 返回。
这个类主要是接口函数 Method 的每个注解。入口函数是 parse。
static RequestFactory parse(Method method, Type responseType, Retrofit retrofit) {
RequestFactoryParser parser = new RequestFactoryParser(method);
parser.parseMethodAnnotations(responseType);
parser.parseParameters(retrofit);
return parser.toRequestFactory(retrofit.baseUrl());
}
先解析方法注解(应用到方法上的注解),比如说 FormUrlEncoded,Headers。得到对应的值。
然后再解析方法参数注解(应用到方法参数上的注解),在解析方法参数注解的时候,会生成一个 requestBuilderActions 数组,对应到每个参数。每个 Action 都对应了每个函数参数的处理。等到具体函数调用的时候,跟函数具体的参数值对应。也就是 RequestFactory 与 Builder 的工作了,这部分是等到运行的时候才能够确定的。
BuiltInConverters 继承自 Converter.Factory,返回的 responseConverter 是 OkHttpResponseBodyConverter 或 VoidConverter,也就是接口方法返回的职能是 OkHttp 的 ResponseBody,或者 Void。 返回的 requestConverter 是 OkHttpRequestBodyConverter,接口方法的参数中如果使用 Body,那 Body 也只能是 OkHttp 的 RequestBody。
VoidConverter: 将 OkHttp 的 ResponseBody 转化为 Void。 OkHttpResponseBodyConverter:将 OkHttp 的 ResponseBody 转化为 OkHttp 的 ResponseBody。如果是 Streaming 标记的接口的话,利用 Utils.readBodyToBytesIfNecessary 缓冲整个 body。 OkHttpRequestBodyConverter:将 OkHttp 的 RequestBody 转化为 OkHttp 的 RequestBody。
一个 Executor,通过 android Handler 将 Runnable 执行在 UI 线程中。
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
这是 Retrofit 中的一个工具类,里面包含了很多范型的检查、操作。另外以及一些基本的工具性的功能。下面是它里面的函数:
checkNotNull <T> T checkNotNull(T object, String message)
检查非空,如果是 null,则抛出 NullPointerException,内容提示为 message。
closeQuietly static void closeQuietly(Closeable closeable)
静默地关闭 Closeable 对象。不会抛出异常
isAnnotationPresent static boolean isAnnotationPresent(Annotation[] annotations,Class<? extends Annotation> cls)
判断 cls 是否是 annotations 里面的一个实例。如果在则返回 true。
readBodyToBytesIfNecessary static ResponseBody readBodyToBytesIfNecessary(final ResponseBody body) throws IOException
如果 body 非 null 的话,把整个 body 读取出来(读取到 buffer),返回再返回一个 ResponseBody。
validateServiceInterface static <T> void validateServiceInterface(Class<T> service)
验证接口是否有效,这个接口就是用户自定义的接口。如果不是接口,或者里面没有任何函数,则抛出 IllegalArgumentException 异常。
getSingleParameterUpperBound public static Type getSingleParameterUpperBound(ParameterizedType type)
该函数获取 type 的单个模版参数的上届。如果 type 有多个类型,函数会抛出异常,如果模版参数不是 WildcardType,则直接返回模版参数类型
hasUnresolvableType public static boolean hasUnresolvableType(Type type)
判断是否有不能分解的类型,比如有 TypeVariable,WildcardType 等
getRawType public static Class<?> getRawType(Type type)
这个方法是从 Gson 里面截取的,获取 type 的实际类型。
methodError static RuntimeException methodError(Method method, String message, Object... args)
static RuntimeException methodError(Throwable cause, Method method, String message,Object... args)
两个重载函数,抛出方法错误异常
getCallResponseType static Type getCallResponseType(Type returnType)
获取返回 Call 的返回类型,必须是模版参数类型,并且 Call 的模版参数不能是 retrofit.Response.class。返回 getSingleParameterUpperBound(returnType)
Retrofit 是很适合扩展的,里面设计的 Call,以及 Converter 就是为了方便扩展使用。
Retrofit 提供的默认的 Converter 只会返回 ResponseBody,如果我们想要返回具体的 Object,我们可以使用另外的第三方包,并且在创建 Retrofit 的时候添加对应的 ConverterFactory。这里有 6 个序列化第三方库:
retrofit 也可以与Rxjava联合起来使用,之前的版本使用范例可以参考http://randomdotnext.com/retrofit-rxjava/
正在开发中,主要是通过扩展 CallAdapter,将之前 Call,转换为 rxjava 需要的 Observable<?>。
Retrofit 整体框架的代码并不多,主要是围绕着 converter,CallAdapter 设计的整个框架。花了两三天时间耐耐心心地把代码也是挺有收获。Retrofit 用到的基本技术是动态代理,Java 注解,Java 范型。另外如果对设计模式很熟悉的话,读起来感觉就会事半功倍。整个架构设计的非常好