声明:本文章基于retrofit:2.3.0
一.Retrofit2中类的介绍
1.retrofit2/http包下的注解 Retrofit2大都是用于构造请求的, 这些注解可以分为三类 :"Http请求方法类","标记类","参数类",具体会在三中描述
2.Call:(接口)类似于OKHttp的Call就是对一个请求的封装,我们一般在接口文件中定义的方法其返回值就是Call<T> 类型.
3.CallAdapter:(接口其中有一个抽象内部类Factory):用于对Call进行操作,包装的类,Retrofit2提供了很多CallAdapter在五中会有描述
4.DefaultCallAdapterFactory:是对CallAdapter.Factory的实现
5.Converter:(接口其中有一个抽象内部类Factory)用于转换数据,如将请求网络返回的Response转换成我们需要的javaBean,Retrofit2提供了很多Converter在四中会有描述.当然不仅仅是针对返回的数据,还能用于一般备注解的参数的转化例如@Body标识的对象做一些操作
6.BuiltInConverters:(实现了Converter.Factory) 是Retrofit2中Converter的默认实现
7.Platform:Android,java8等平台信息的封装,可获取平台信息,并且每个平台都有对应的回调接口,比如Android平台就会具有回调到主线程的接口.
8.ServiceMethod:从接口方法到Http请求(OKHttp的Call)的转换器,也是使用的构造器模式.
二.对最简单的Retrofit2访问网络的代码进行源码阅读
//配置Retrofit,并获取Retrofit实例
Retrofit.Builder builder = new Retrofit.Builder();
builder .addConverterFactory(GsonConverterFactory.create());
builder .baseUrl("http://www.ccholterserver.com:44444/");
Retrofit retrofit =builder .build();
//获取接口实例
RetrofitDemo retrofitDemo = retrofit.create(RetrofitDemo.class);
Call<ResponseBody> call = retrofitDemo.getImage();
//执行请求
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
ResponseBody body = response.body();
try {
Log.e("MainActivity", body.string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {}
});
1.在执行第一句代码创建Retrofit.Builder的时候
Retrofit.Builder builder = new Retrofit.Builder();
系统首先会调用Platform.get()判断当前的平台是什么,
public Builder() {
this(Platform.get());
}
然后对平台信息进行记录,并为Retrofit2添加一个默认的ConverterFactory(转换器)
Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());
}
在Retrofit中有一个存储ConverterFactory的集合
private final List<Converter.Factory> converterFactories = new ArrayList<>();
2.第二句第三句代码是对Retrofit.Builder进行配置
builder .addConverterFactory(GsonConverterFactory.create());
builder .baseUrl("http://www.ccholterserver.com:44444/");
在执行 builder .addConverterFactory(GsonConverterFactory.create());的时候也就是给converterFactories 集合中再添加了一个ConverterFactory.
/** Add converter factory for serialization and deserialization of objects. */
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
在执行builder .baseUrl("http://www.ccholterserver.com:44444/");这句代码的时候首先会对baseUrl进行检查,如果没有问题则转换为HttpUrl然后进行记录到Builder中
public Builder baseUrl(String baseUrl) {
//检查baseUrl 是否为null
checkNotNull(baseUrl, "baseUrl == null");
//将String型的baseUrl转换成HttpUrl
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
//检查baseUrl
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
//对baseUrl 进行记录
this.baseUrl = baseUrl;
return this;
}
3.第四句代码** Retrofit retrofit =builder .build();**执行了builder.build()方法,这个就是创建一个Retrofit然后将builder记录的数据传递给Retrofit.
public Retrofit build() {
//如果baseUrl 为空 就抛异常
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//如果用户没有设置OkHttpClient的话,Retrofit会自己创建一个
//OkHttpClient对象
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//如果用户没有设置callbackExecutor,那么Retrofit就会将该平台默认
//的Executor设置给自己
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 将用户设置的CallAdapter.Factory进行拷贝并添加该平台默认的
//CallAdapter.Factory
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 将用户设置的Converter.Factory进行拷贝,默认的Converter.Factory
//已经在创建Builder的时候设置了
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
//创建一个Retrofit实例,并返回
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
//在创建Retrofit实例的时候其实也没有做其他的事情,只是将从Builder中传
//递过来的参数进行了记录
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
@Nullable 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;
}
4.下面执行的第五局代码** RetrofitDemo retrofitDemo = retrofit.create(RetrofitDemo.class);**就是通过Retrofit实例将我们写url的接口文件进行实例化.其实里面是通过动态代理来对接口进行实例化,然后在调用接口中方法的时候都会先调用代理中InvocationHandler中的invoke()方法.
public <T> T create(final Class<T> service) {
//对传入的interface进行检查
Utils.validateServiceInterface(service);
//如果我们设置了validateEagerly为true,那么Retrofit就会提前检查传入
//Interface中的方法
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//返回传入interface的实例
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, @Nullable Object[] args)
throws Throwable {
//如果传入的method是object的中定义的方法那就直接执行
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//isDefaultMethod()这个方法其实只是对java8平台上的有效,Android平台上直接返回的是false
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//将接口中定义的方法封装成ServiceMethod,其实也就是获取到接口中方法的注解,和参数来进行转换
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//将ServiceMethod再次封装成OkHttpCall(实现了Retrofit的Call接口)
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//返回一个Retrofit的Call对象(就是ExecutorCallAdapterFactory中的内部类ExecutorCallbackCall)
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
5.下面执行第六句代码Call<ResponseBody> call = retrofitDemo.getImage();这个流程就是执行InvocationHandler的invoke方法 在上面4 中已经有注释了,在这里我们来看看** return serviceMethod.callAdapter.adapt(okHttpCall);**这句代码中callAdapter道理是如何确定为 ExecutorCallAdapterFactory,最后返回的结果也就是ExecutorCallAdapterFactory中的内部类ExecutorCallbackCall
首先执行serviceMethod.callAdapter这句代码,那么我们就来看看这个callAdapter成员变量在哪里确定的
在ServiceMethod的Builder.build()方法中找到了
public ServiceMethod build() {
//获取到callAdapter
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
...
}
然后执行了createCallAdapter()方法,在这里调用了Retrofit的callAdapter()方法
private CallAdapter<T, R> createCallAdapter() {
...
Annotation[] annotations = method.getAnnotations();
try {
//获取callAdapter
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
下面就到了Retrofit的callAdapter方法中
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
它又调用了自己的nextCallAdapter方法,就在这里返回了CallAdapter
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
//遍历存CallAdapter.Factory的集合,然后找到adapter.Factory,然后调用get()方法返回//遍历存CallAdapter.Factory的集合,然后找到adapter.Factory
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
...
}
到目前为止我们只给adapterFactories这个集合中转入了一个CallAdapter.Factory,那就是在创建Retrofit的时候调用adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));这句代码向adapterFactories中添加了CallAdapter.Factory
我们已经知道了这里的platform是Android 所以只需要看看Android中的defaultCallAdapterFactory就可以了
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
到现在我们终于知道那个serviceMethod.callAdapter就是ExecutorCallAdapterFactory了
6.最后执行了第七句代码** call.enqueue(new Callback<ResponseBody>() {...}** 首先我们通过 4,5已经知道了这个call是ExecutorCallAdapterFactory中的内部类ExecutorCallbackCall,所以我们直接来看ExecutorCallbackCall的enqueue()方法.首先会调用callbackExecutor的enqueue(),这里的callbackExecutor就是OKHttpCall,OKHttpCall的enqueue()方法中首先会创造一个OKHttp的Call然后执行Call.enqueue方法执行请求,最后使用Converter对请求回来的Response进行转换
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//创建请求
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//执行请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
//对Response进行转换
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();
}
}
});
}
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
......
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//调用ServiceMethod的toResponse的方法使用Converter进行转换
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
//调用Converter的convert方法转换
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
在这里我们可以明显的看出来Retrofit中使用callbackExecutor将线程从子线程切换到了主线程,使onResponse()和onFailure()运行在了主线程,这里的callbackExecutor就是Android中的MainThreadExecutor,它在Retrofit的Builder.build方法中实例化,具体可以看 3
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "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);
}
});
}
});
}
Retrofit2到OKHttp的调用流程图
三.Retrofit2中注解分类及用法
1.HTTP请求方法:下表中列举的方法除了Http都是Http中的请求方法,而Http可以代替其他所有
2.标记类
3.参数类
四.Retrofit2中提供的Converter
Converter | Gradle依赖 |
---|---|
Gson | com.squareup.retrofit2:converter-gson:2.0.2 |
Jackson | com.squareup.retrofit2:converter-jackson:2.0.2 |
Moshi | com.squareup.retrofit2:converter-moshi:2.0.2 |
Protobuf | com.squareup.retrofit2:converter-protobuf:2.0.2 |
Wire | com.squareup.retrofit2:converter-wire:2.0.2 |
Simple XML | com.squareup.retrofit2:converter-simplexml:2.0.2 |
Scalars | com.squareup.retrofit2:converter-scalars:2.0.2 |
五.Retrofit2中提供的CallAdapter
CallAdapter | Gradle依赖 |
---|---|
guava | com.squareup.retrofit2:adapter-guava:2.0.2 |
Java8 | com.squareup.retrofit2:adapter-java8:2.0.2 |
rxjava | com.squareup.retrofit2:adapter-rxjava:2.0.2 |
六.值得学习的代码
1.获取当前是那个平台(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();
}
七.总结及问题
1.Retrofit2和OKHttp的关系
Retrofit2其实就是对OKHttp进行了封装,底层请求网络完全就是OKHttp,不过他将请求回来的结果发送到了主线程.
2.Retrofit2中的baseUrl可以不以""结尾,单看其他的博客说有的版本是必须要加上""的所以我们最好加上,避免版本兼容问题
3.Retrofit2中的baseUrl不能为null,或者为空字符串(或者错误的url).当为null的话会报
throw new NullPointerException("baseUrl == null");
如果为空字符串(或者错误的url) 的话回报(但是也有可能控制台什么错误都不会输出,但是debug的话确实走到这句代码,我就遇到这样的问题)
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
4.Retrofit2中Path和Query的区别
Path是用于url中路径的设置(Url中"?"之前是路径)
Query 适用于Url中参数的设置(Url中"?"之后是参数)
下面举例
//正确的写法
@GET("users")
Call<List<User>> getUsersBySort(@Query("sortby") String sort);
//错误的写法
@GET("users?sortby={sortby}")
Call<List<User>> getUsersBySort(@Path("sortby") String sort);
5.自定义Converter.Fectory需要注意的
- responseBodyConverter 主要是对应@Body注解,完成ResponseBody到实际的返回类型的转化,这个类型对应Call<XXX>里面的泛型XXX,其实@Part等注解也会需要responseBodyConverter,只不过我们的参数类型都是RequestBody,由默认的converter处理了。
2.requestBodyConverter 完成对象到RequestBody的构造。
3.一定要注意,检查type如果不是自己能处理的类型,记得return null (因为可以添加多个,你不能处理return null ,还会去遍历后面的converter).
八.参考文章
http://www.jianshu.com/p/308f3c54abdd
http://blog.csdn.net/lmj623565791/article/details/51304204