现在的项目界面都是按iOS的风格,虽然界面无法发挥出我们大Android的风格,网络框架动不动就是mvp+ okhttp +retrofit+rxjava,mvvm+databind的模式,但是网络框架什么的,我们也可以与时俱进的嘛。
今天就在此聊聊retrofit的相关内容,也可以算是给自己的这几周没有更新文章的一个交代吧。
首先关于使用方法,我们可以从官网上了解。
官网地址(http://square.github.io/retrofit/)
网络基本请求方法(官网)
Introduction
Retrofit turns your HTTP API into a Java interface.
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
The Retrofit
class generates an implementation of the GitHubService
interface.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Each Call
from the created GitHubService
can make a synchronous or asynchronous HTTP request to the remote webserver.
Call<List<Repo>> repos = service.listRepos("octocat");
Use annotations to describe the HTTP request:
根据上述官网描述,简单总结为以下的几点:
1、创建一个接口来进行HTTP请求;
2、通过new Retrofit.Builde的builder构建出一个retrofit对象;
3、使用retrofit.create获取该网络接口请求实例;
4、由请求接口实例返回一个Call对象;
5、进行网络(同步、异步)请求
下面分析上述的几点:
public final class Retrofit {
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
private final okhttp3.Call.Factory callFactory;
private final HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories;
private final List<CallAdapter.Factory> adapterFactories;
private final Executor callbackExecutor;
private final boolean validateEagerly;
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
首先通过Retorfit源码我们可以了解到它底层网络框架是基于okhttp实现的,整体的实现过程就是客户端通过给retrofit发送网络请求,构建一个Request请求,如队列,然后通过Excutor执行,进入Looper循环查找该出该request并执行,执行完成通过解析返回call对象然后交给客户端做相关处理。图解如下:
下面分析下总结的几点:
1、创建一个接口来进行HTTP请求,这就是写一个API接口类来存放所需要实现的服务端接口类。
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
new Retrofit.Builde构建对象,创建Retrofit实例,我们现在通过源码分析下Builder到底做了什么?
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
Builder源码部分:
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder callbackExecutor(Executor executor) {
this.callbackExecutor = checkNotNull(executor, "executor == null");
return this;
}
public Builder validateEagerly(boolean validateEagerly) {
this.validateEagerly = validateEagerly;
return this;
}
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
在源码中的builder方法我们可以看到除了baseurl是必须的参数,其他配置参数都可以为空(选配参数)。
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
简单说下
Converter<F, T>:数据转换器,用来将HTTP请求返回结果由F类型转换为T类型,或者将HTTP请求类型F转换为T,也就是我们通过添加的转换器
addConverterFactory方法,可以将call对象的数据返回成我们所需要的数据格式。
.addConverterFactory(RDConverterFactory.create())
CallAdapter<R, T>:请求适配器,用于将retrofit2.Call<R>网络请求类型转换为T类型,简单的说就是我们网络请求参数封装的格式。不过到目前为止我还没有用这个
在
.build()
之前看下builder构造方法:
Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
当我们调用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
首先进去Builder构造方法,在该方法中我们的converterFactories添加了一个
BuiltInConverters对象,我们知道converterFactories是处理HTTP返回结果进行
类型转换或者将HTTP请求体进行类型转换。现在看下源码中BuiltInConverters式怎样进行转换的?
final class BuiltInConverters extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == ResponseBody.class) {
if (Utils.isAnnotationPresent(annotations, Streaming.class)) {
return StreamingResponseBodyConverter.INSTANCE;
}
return BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
return RequestBodyConverter.INSTANCE;
}
return null;
}
@Override public Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == String.class) {
return StringConverter.INSTANCE;
}
return null;
}
static final class StringConverter implements Converter<String, String> {
static final StringConverter INSTANCE = new StringConverter();
@Override public String convert(String value) throws IOException {
return value;
}
}
static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();
@Override public Void convert(ResponseBody value) throws IOException {
value.close();
return null;
}
}
static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
@Override public RequestBody convert(RequestBody value) throws IOException {
return value;
}
}
static final class StreamingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
return value;
}
}
static final class BufferingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
try {
// Buffer the entire body to avoid future I/O.
return Utils.buffer(value);
} finally {
value.close();
}
}
}
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
}
返回结果转换的时候,有3种情况:
1、如果返回类型是ResponseBody类型,那么可能返回的是:StreamingResponseBodyConverter.INSTANCE或者BufferingResponseBodyConverter.INSTANCE,再跟踪进去这两个类里面的convert函数:
@Override public ResponseBody convert(ResponseBody value){···}
发现传入的是ResponseBody,返回的也是ResponseBody(BufferingResponseBodyConverter里面有进行特殊处理,主要是为了去除future I/O),所以我们可以认为BuiltInConverters对HTTP返回结果没有进行转换处理。
static final class StreamingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
return value;
}
}
static final class BufferingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
try {
// Buffer the entire body to avoid future I/O.
return Utils.buffer(value);
} finally {
value.close();
}
}
}
2、如果返回类型是Void类型,那么最终就将ResponseBody资源关闭后,直接返回null。
static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();
@Override public Void convert(ResponseBody value) throws IOException {
value.close();
return null;
}
}
3、如果返回类型不是ResponseBody和Void类型,直接返回null。
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == ResponseBody.class) {
if (Utils.isAnnotationPresent(annotations, Streaming.class)) {
return StreamingResponseBodyConverter.INSTANCE;
}
return BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
同理可知
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
return RequestBodyConverter.INSTANCE;
}
return null;
}
static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
@Override public RequestBody convert(RequestBody value) throws IOException {
return value;
}
}
如果是RequestBody就不转换,直接返回,如果不是RequestBody则返回null。
从结构图来看,BuiltInConverter只转换ResponseBody和RequestBody,其他的都不进行转换。
分析了Builder的构造后终于可以进入到builder构造方法构建出一个Retrofit对象了。
/**
* Create the {@link Retrofit} instance using the configured values.
* <p>
* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
* OkHttpClient} will be created and used.
*/
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//callFactory默认为OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
从源码中我们知道callFactory默认是OKhttpClient,所以说我们除了需要传递一个baseUrl参数,其他可选配置参数都会为我们提供一个默认值。
好了build我们就先了解这么多了,至于深入的就需要读者自己去研究了。
现在我们来说下create方法
GitHubService service = retrofit.create(GitHubService.class);
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
我们可以看到create方法返回的是一个 (T) Proxy.newProxyInstance产生的一个动态代理对象,通过InvocationHandler拦截进入到invoke函数中。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler invocationHandler)
throws IllegalArgumentException {
if (invocationHandler == null) {
throw new NullPointerException("invocationHandler == null");
}
Exception cause;
try {
return getProxyClass(loader, interfaces)
.getConstructor(InvocationHandler.class)
.newInstance(invocationHandler);
} catch (NoSuchMethodException e) {
cause = e;
} catch (IllegalAccessException e) {
cause = e;
} catch (InstantiationException e) {
cause = e;
} catch (InvocationTargetException e) {
cause = e;
}
AssertionError error = new AssertionError();
error.initCause(cause);
throw error;
}
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
最重要的就是
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
主要做的就是对接口方法注解进行解析,最终生成一个Request。关于create方法先说到这。
最后通过callInit.enqueue方法进行真正发送网络请求,通过OkHttp代码片段可以
可以看到,请求成功的时候,会调用parseResponse得到一个我们需要的Response<T>类型对象,在这个方法中可以将我们的数据转换成我们自己需要的数据格式
//OkHttpCall.enqueue片段代码
call.enqueue(new okhttp3.Callback()
{
@Override
public void onResponse (okhttp3.Call call, okhttp3.Response rawResponse)throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure (okhttp3.Call call, IOException e){
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
retrofit就到此结束了,其中的分析过程不是那么好,那么的详细完整,也算使用这个框架的部分心得了吧,如果你有更好的见解,欢迎探讨学习,期待你的回复。