Android技能树 — 网络小结(7)之 Retrofit源码
前言:
哈哈,其实写的还是很水,各位原谅我O(∩_∩)O。
介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看,最好可以指出我的错误,让我也能纠正。
1.讲解相关的整个网络体系结构:
2.讲解相关网络的重要知识点,比如很多人都听过相关网络方面的名词,但是仅限于听过而已,什么tcp ,udp ,socket ,websocket, http ,https ,然后webservice是啥,跟websocket很像,socket和websocket啥关系长的也很像,session,token,cookie又是啥。
Android技能树 — 网络小结(3)之HTTP/HTTPS
Android技能树 — 网络小结(4)之socket/websocket/webservice
相关网络知识点小结- cookie/session/token(待写)
3.相关的第三方框架的源码解析,毕竟现在面试个大点的公司,okhttp和retrofit源码是必问的。
Android技能树 — 网络小结(6)之 OkHttp超超超超超超超详细解析
Android技能树 — 网络小结(7)之 Retrofit源码详细解析
正文
因为我平时使用的都是Rxjava2 + Retrofit ,所以我相关的源码解析都是配合RxJava来的,而不是Call返回对象。
读本文的我推荐大家最好对OKHttp源码有所了解,再来看本文,因为Retrofit内部还是通过OkHttp发出网络请求。大家也可以看我前面写的:Android技能树 — 网络小结之 OkHttp超超超超超超超详细解析,
<font color = "red">同时本文不会再去教大家Retrofit的基础使用,如果要看一些简单使用,可以看下面的一些推荐博客:</font>
Android Retrofit 2.0 的详细 使用攻略(含实例讲解)
Android:Retrofit 结合 RxJava的优雅使用(含实例教程)
我们先上一张别的大佬博客中的一张图:
这个图画的很好,但是这个图更多的是从大局观来看,所以如果对于源码不是有一些基础了解的话,看这个图很容易就忘记。
看过我的Okhttp源码分析的文章:Android技能树 — 网络小结之 OkHttp超超超超超超超详细解析,我们文中的Okhttp流程图就是跟着源码一步步来画的。我更喜欢是跟着源码一步步来画流程图(PS:其实是我水平太差了,无法一下子总结处第三方库的各种设计模式的使用),所以Retrofit我也画了下面这个图:
而等会我们分析完这个跟着源码分析的流程图后,再回头看上面的别人博客中的总结的Retrofit结构图,就会很简单了。
首先我们来确定总体大纲:
我们知道我们的目标是要发起一次网络请求,他有这么几步:
- 告诉它一些基本信息,比如url地址,网络请求方式(get、post、...等),请求参数值。然后拼装成一个标准的网络Request请求的格式发出去。<font color = "red">所以这里有二步动作:1.先解析我们写的参数,2.再解析完后拼装成标准的网络Request请求格式</font>
- 发出请求后,接收到了后台的Response返回结果,我们要把Resonse转换成我们想要的返回结果。但是我们写的想要的返回结果又有二大关键地方,我们平常的返回结果可能是
X <Y>
,我们先来看外面的X的类型
,比如我们常见的返回结果是Call<Y> 和 Observable<Y>
,所以我们在转换的时候一是要考虑最外面的那个返回类型的转换。另外一个是Y的类型
,也就是里面我们具体写的Bean对象,比如我们直接返回字符串,那可能就是Observable<String>
,又或者是自己定义的xxxBean对象,那就是Observable<xxxBean>
。<font color = "red">所以我们要有二类转换:1.外层的结果类型,比如Call或者Observable等,2.是泛型里面填的具体的Bean对象类型</font>
所以我们总结起来就需要四步:
<font color = "red">
- 解析并拿到我们写的一些参数(url,请求方式(post/get),请求参数......)
- 根据我们写的参数,拼成一个网络请求Request,去帮我们发起请求。
- Response如何转换成Call或者Observable等返回类型,和第4步中的Bean对象拼成了Call《Bean》或者Observable《Bean》
- Response如何转换成我们所需要的具体的Bean对象。
</font>
没错,下次别人问你,你就心里有数了,到底Retrofit做了什么内容,你就跟别人说很简单啦,大致做了上面四步,逼格一下子提高了。。
1. 创建Retrofit对象
我这里直接先把创建Retrofit的对象的代码写上:
Retrofit retrofit = new Retrofit.Builder()
.client(new OkHttpClient())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://xxxx.com/")
.build();
不要问创建Retrofit的各自的方法是干嘛的,我们后面会一步步讲解。
2. 如何解析并拿到我们写的参数
我们知道我们平常是这样写的:
我们随便写一个常见的获取某个用户的个人信息接口来说明:
InfoApi.java:
interface InfoApi{
@GET("userinfo.do")
Observable<UserBean> getInfo(@Query("name") String nameStr);
}
那我们要拿到:
- path值:上面创建Retrofit时候传入的baseUrl +
userinfo.do
="https://xxxx.com/userinfo.do"
- 网络请求的方式:
GET请求
- 发送的参数query :
name=nameStr
最终我们发现是GET请求,所以这么拼在一起:path + "?" + query = http://xxxx/userinfo.do?name=nameStr
所以我们来看如何一步步拿到相关参数:
我们知道上面写的InfoApi.java
是要被retrofit加载进去的:
retrofit.create(InfoApi.class);
所以我们要来看create
方法的具体操作前,我们先来了解一下基础知识,那就是代理模式,如果知道代理模式的,直接可以忽略此处,直接往下看。
2.1 create方法:
在看create代码之间,我们要先学会代理模式相关知识
本来也想一步步长篇大论的写下,但是后来看到一篇不错的文章,写的挺仔细的:java动态代理实现与原理详细分析 ,希望大家能仔细看完,在看下面的内容。
我们点进去查看具体的代码:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (this.validateEagerly) {
this.eagerlyValidateMethods(service);
}
//'使用了代理模式'
return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
private final Platform platform = Platform.get();
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
} else if (this.platform.isDefaultMethod(method)) {
return this.platform.invokeDefaultMethod(method, service, proxy, args);
} else {
//'我们可以看到我们写的接口里面的的method传入到了loadServiceMethod方法里面,从而得到了我们定义在method上面的相关参数信息。'
ServiceMethod<Object, Object> serviceMethod = Retrofit.this.loadServiceMethod(method);
//'我们传入的方法的参数args和上面获得的ServiceMethod,一起传入OkHttpCall构造函数中,得到OkHttpCall对象'
OkHttpCall<Object> okHttpCall = new OkHttpCall(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
}
});
}
我们可以看到我们调用的getInfo
这个method方法传入了:
ServiceMethod<Object, Object> serviceMethod = Retrofit.this.loadServiceMethod(method);
我们进去查看:
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//'从缓存中去读'
ServiceMethod<?, ?> result = (ServiceMethod)this.serviceMethodCache.get(method);
if (result != null) {
return result;
} else {
Map var3 = this.serviceMethodCache;
synchronized(this.serviceMethodCache) {
result = (ServiceMethod)this.serviceMethodCache.get(method);
if (result == null) {
//'如果缓存中没有,则新建'
result = (new retrofit2.ServiceMethod.Builder(this, method)).build();
//'新建完后再放入缓存中'
this.serviceMethodCache.put(method, result);
}
return result;
}
}
}
我们可以看到新建的方法:
(new retrofit2.ServiceMethod.Builder(this, method)).build();
我们来看ServiceMethod类下的Builder的构造函数:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//'Java特有的方法,可以获取Java方法上面的注解标识,比如:@POST,@GET'
this.methodAnnotations = method.getAnnotations();
//'获取方法参数里面定义的参数类型,比如:String,boolean'
this.parameterTypes = method.getGenericParameterTypes();
//'获取方法里面的注解标识,比如:@Query,@Path'
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
是不是一下子就知道了,原来是通过这样的方式拿到了我们写在方法上面的一些参数值,如果还不清楚Method的这几个方法,可以看下面的相关链接:</br>
Java获取类、方法、属性上的注解</br>
java.lang.reflect.Method.getGenericParameterTypes()方法示例.</br>
使用反射获得参数列表里的注解getParameterAnnotations.
我们创建ServiceMethod因为是使用的Builder模式,所以最终要调用build()方法来创建实例:
public ServiceMethod build() {
//'创建了CallAdapter对象,具体干嘛用的,具体后面会讲解'
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ “ is not a valid response body type. Did you mean ResponseBody?”);
}
//'创建了ResponseConverter对象,具体后面会讲解'
responseConverter = createResponseConverter();
//'对于我们写的接口请求方法的方法上面的注解进行相关判断,'
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//'因为进行方法上面注解的解析了,所以httpMethod的也就相应的被赋值了,
如果为空,就说明你写的请求接口方法没有写@GET等,就会抛出异常'
if (httpMethod == null) {
throw methodError(“HTTP method annotation is required (e.g., @GET, @POST, etc.).”);
}
//'因为上面解析了,所以比如我们发现是@GET请求,这时候hasBody会是false,如果你还用了Multipart注解,就会报错了,他要求是要有request body的,@GET请求是不能使用Multipart的'
if (!hasBody) {
if (isMultipart) {
throw methodError(
“Multipart can only be specified on HTTP methods with request body (e.g., @POST).”);
}
//'同上,表单提交是一定要求有request body的'
if (isFormEncoded) {
throw methodError(“FormUrlEncoded can only be specified on HTTP methods with
+ request body (e.g., @POST).”);
}
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
//'遍历我们获取的方法里面的注解集合,比如@Query,@Path等'
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, “Parameter type must not include a type variable or wildcard: %s”,
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, “No Retrofit annotation found.”);
}
//'然后对我们写的方法内部参数注解进行判断,看写的是否正确等
这里的判断很长,比如如果你用的是注解@Body,那么先判断你是否用了方法上面的@FormEncode注解或者@Multipart注解,
不然就报错,然后因为我们填的参数是对象了,所以内部需要通过RequestBodyConverter来进行转换,把我们传的对象,变成了RequestBody对象。
具体很多很多判断,各种注解的判断我都不一一讲了,大家只要进去看方法详细代码就可以了。'
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError(“Missing either @%s URL or @Url parameter.”, httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError(“Non-body HTTP method cannot contain @Body.”);
}
if (isFormEncoded && !gotField) {
throw methodError(“Form-encoded method must contain at least one @Field.”);
}
if (isMultipart && !gotPart) {
throw methodError(“Multipart method must contain at least one @Part.”);
}
return new ServiceMethod<>(this);
}
好,我们已经成功拿到了我们的方法中的红色框出来的部分,绿色的部分我们还没有获取。
而代理模式的invoke方法里面的参数 @Nullable Object[] args,就是我们具体传入的参数,比如我这么写:
getInfo("青蛙要fly");
args里面就有了我们传入的"青蛙要fly"
字符串。这样我们是不是就获取了上面的其中一个绿色框nameStr的内容了。
我们拿到包含了这些红色框参数的ServiceMethod对象后,加上我们传入的绿色的框的nameStr的具体的值
,我们已经可以进行网络Request请求的所必要的参数了 (另外一个绿色的框只是用来最后网络请求成功后拿到的Response进行转换,所以这时候不知道都不影响Request请求)
我们可以看到我们获得到的信息,又用来生成了OkHttpCall对象,然后调用了serviceMethod.adapt(okHttpCall);
方法。
那我们可以看到create接下去已经没有其他代码了,所以serviceMethod.adapt(okHttpCall);
肯定会帮我们用刚才拿到的已知参数,帮我们拼成Request,完成一次网络请求。
3.根据我们写的参数,拼成Request请求
我们上面已经说到了进入了serviceMethod.adapt(okHttpCall);
方法了,我们点进去查看:
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
我们可以看到是调用了callAdapter类的adapt方法。那这个callAdapter对象又是什么呢?
还记不记得我们第一大步:创建Retrofit对象时候的代码:
Retrofit retrofit = new Retrofit.Builder()
.client(new OkHttpClient())
//'这里传入了CallAdapterFactory,而Factory类是用来创建具体的CallAdapter对象的工厂类'
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://xxxx.com/")
.build();
所以本文中我们使用的CallAdapter是RxJava2CallAdapterFactory创建的,我们先来看ServiceMethod里面创建CallAdapter的方法:
private CallAdapter<T, R> createCallAdapter() {
//'我们上面的接口请求方法绿色框里面的返回类型还没有拿到的,终于在这里拿到了'
Type returnType = method.getGenericReturnType();
//'如果方法的返回结果包含了泛型表达式、泛型、泛型数组,就抛出异常'
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
“Method return type must not include a type variable or wildcard: %s”, returnType);
}
//'如果方法的返回结果是void,则抛出异常'
if (returnType == void.class) {
throw methodError(“Service methods cannot return void.”);
}
//'我们前面提过的,获取方法上的注解,比如@GET等'
Annotation[] annotations = method.getAnnotations();
try {
//'拿着我们的接口请求方法的返回对象及方法上的注解信息,'
//'去通过Retrofit类的callAdapter类去生成一个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方法,我们不看都知道,通过我们前面创建Retrofit对象时候传入的addCallAdapterFactory的工厂类来创建具体的CallAdapter,当然我们具体还是要具体代码一步步来看过程。
我们在调用addCallAdapterFactory加入我们的RxJava2CallAdapterFactory.create()
,所以先来看下addCallAdapterFactory方法做了什么:
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
我们可以简单的看到,就是把我们的Factory工厂类对象加入到private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
这个List队列中而已。
那这个队列到底都加了哪些工厂类的,如果我在创建Retrofit对象时候不调用addCallAdapterFactory
方法,难道这个队列就是空的????那又怎么去生成CallAdapter对象?
首先肯定要加入我们自己传入的Factory,有可能一个,也可能传入多个:
Retrofit retrofit = new Retrofit.Builder()
........
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addCallAdapterFactory(xxxxxxCallAdapterFactory.create())
.addCallAdapterFactory(yyyyyyCallAdapterFactory.create())
........
........
.build();
但是为了防止我们建立Retrofit对象时候不调用addCallAdapterFactory传入自己的Factory,所以本身这个队列还会加入默认的Factory:
//'看名字就知道,加入平台的默认的CallAdapterFactory(有java8 和 Android Platform,我们这里肯定是Android)'
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
当然这个ExecutorCallAdapterFactory肯定是继承了CallAdapter.Factory:
我们已经知道了我们的CallAdapterFactory队列里面包含了哪些工厂类了。接下来我们再来具体的Retrofit的callAdapter的方法:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
//'因为可能有多个CallAdapterFactory工厂类,所以要每个工厂类都去试一下,有一个成功就直接返回了'
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = callAdapterFactories.indexOf(skipPast) + 1;
//'循环遍历所有的CallAdapterFactory,然后哪个能成功生成CallAdapter,就直接返回'
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//'如果所有的CallAdapterFctory都不能使用,就拼接字符串,抛出异常'
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
有可能有人会问,为什么CallAdapterFactory有可能生成CallAdapter不成功??还要一个个去遍历?
因为我们同时传入了我们需要返回的对象的类型传入到了CallAdapterFactory中,你说如果你是默认的ExecutorCallAdapterFactory
工厂类,你却传入了Rxjava的返回相关参数,比如我们例子中的Observable<UserBean>
,它的代码里面都不认识这种返回类型,怎么帮你去生成对象,而且代码也是加了判断,如果返回类型不是Call类型,直接就退出了。
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//'如果不是Call.class,直接退出生成CallAdapter对象'
if (getRawType(returnType) != Call.class) {
return null;
}
.......
.......
}
所以我们来看下RxJava2CallAdapterFactory里面怎么生成相应的CallAdapter的:
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
//'如果我们的返回类型是Completable,就直接返回RxJava2CallAdapter对象,里面的responseType是void'
if (rawType == Completable.class) {
// Completable is not parameterized (which is what the rest of this method deals with) so it
// can only be created with a single configuration.
return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
false, true);
}
//'判断是否是Flowable或者Single或者Maybe'
boolean isFlowable = rawType == Flowable.class;
boolean isSingle = rawType == Single.class;
boolean isMaybe = rawType == Maybe.class;
//'如果既不是上面三种又不是Observable类型,直接返回null'
if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
return null;
}
boolean isResult = false;
boolean isBody = false;
Type responseType;
//'如果不是泛型类的,比如Observable<XXXX> ,则抛异常'
if (!(returnType instanceof ParameterizedType)) {
String name = isFlowable ? "Flowable"
: isSingle ? "Single"
: isMaybe ? "Maybe" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + "<Foo> or " + name + "<? extends Foo>");
}
//'获取泛型中的具体参数,比如Observable<xxxBean>中的xxxBean的type'
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
//'获取xxxBean具体的Class对象'
Class<?> rawObservableType = getRawType(observableType);
//'判断我们上面获取的泛型内容(xxxBean)是不是Response'
if (rawObservableType == Response.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Response must be parameterized"
+ " as Response<Foo> or Response<? extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
//'判断我们上面获取的泛型内容(xxxBean)是不是Result'
} else if (rawObservableType == Result.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Result must be parameterized"
+ " as Result<Foo> or Result<? extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
isResult = true;
} else {
//'我们平常开发泛型里面填的肯定是自己的Bean对象
//所以最后走的是这里的代码'
responseType = observableType;
//'同时isBody设置为true'
isBody = true;
}
//'生成具体的Rxjava2CallAdapter对象'
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
既然我们CallAdapter对象也建立完了,我们回到最刚开始的地方,还记得我们前面分析的代码是到了callAdapter.adapt(okHttpCall)
(如果忘记的同学,可以重新回头看下)。
所以我们现在已经建立的Rxjava2CallAdapter对象了,我们来看下它的adapt方法:
@Override public Object adapt(Call<R> call) {
/**
'很多人会说这个isAsync,是否异步是哪里设置的,
其实就是再我们传入Factory对象时候建立的。
Retrofit retrofit = new Retrofit.Builder()
.client(new OkHttpClient())
我们看见创建Factory对象,可以是createAsync()或者create()方法二种来创建,从而决定是同步还是异步操作
.addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync())
或者是
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()
.build();'
*/
//'我们可以看到上面根据是否异步,建立不同的Observable对象,我们用复杂点的来讲解吧,
就当我们建立的时候使用的是RxJava2CallAdapterFactory.createAsync()方法,所以拿到的对象是CallEnqueueObservable'
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
//'因为我们Observable<xxxBean>里面包含的是自己Bean,所以建立的时候isBody = true;'
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
//'所以我们的Observable为BodyObservable'
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
//'所以最终返回了BodyObservable<CallEnqueueObservable>'
return observable;
}
BodyObservable看名字就知道是一个自定义Observable:
final class BodyObservable<T> extends Observable<T> {
private final Observable<Response<T>> upstream;
BodyObservable(Observable<Response<T>> upstream) {
this.upstream = upstream;
}
@Override protected void subscribeActual(Observer<? super T> observer) {
//'当有Observer注册我们的Observable的时候,
其实是我们前面的传入的CallEnqueueObservable去注册了
一个BodyObserver<我们自己写的Observer>'
upstream.subscribe(new BodyObserver<T>(observer));
}
}
所以核心还是我们传入的CallEnqueueObservable
这个Observable,所以最后还是要看这个类的源码:
final class CallEnqueueObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallEnqueueObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
//'我们可以看到简历了一个CallCallback对象,传入了用户写的我们前面创建的OkHttpCall对象和用户写的observer对象'
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
//'然后调用了call的enqueue方法,
因为是OkHttpCall对象,所以我们直接看OkHttpCall对象的enqueue方法即可'
call.enqueue(callback);
}
private static final class CallCallback<T> implements Disposable, Callback<T> {
.......
.......
.......
}
}
OkHttpCall的enqueue方法:
@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 {
//'创建Okhttp3的Call对象(毕竟最后发起网络请求是Okhttp,也要使用它的Call对象)'
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//'常规Okhttp的操作,call.enqueue方法发起异步请求,估计大家都看得懂,我就不多介绍了,我们直接看拿到返回的数据处理'
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//'我们这里成功的拿到了Okhttp3.Response对象,
所以使用parseResponse方法将rawResponse对象转换成Retrofit的Response对象'
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
到这里,我们已经成功的发送了网络请求,并且拿到了主句
4. 如何将Resonse转换成最终我们想要的结果对象
我们上面可以看到我们是讲OkHttp3.Response对象转换成了Retrofit.Response对象,我们具体来看下:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
//'把Okhttp3.Response中的body部分取出来'
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
//'我们就当成功请求回来的,所以code是200'
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//'核心代码:
把body部分,通过toResponse方法,变成我们写入的泛型(也就是Observable<xxxBean>这个xxxBean对象'
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;
}
}
所以最终我们发现又回到了serviceMethod里面了,相关的方法调用都在这里面:
R toResponse(ResponseBody body) throws IOException {
//'可以看到我们通过responseConverter转换器来对body部分进行了转换'
return responseConverter.convert(body);
}
这个responseConverter又是怎么来的呢?我们再回到创建Retrofit对象的地方:
Retrofit retrofit = new Retrofit.Builder()
.client(new OkHttpClient())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//'看见了ConverterFactory没有,就是这里传入了我们的转换器对象'
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://xxxx.com/")
.build();
我们来看下具体的代码:
public final class GsonConverterFactory extends Converter.Factory {
//'可以看到默认内部使用的是GSON来进行转换'
public static GsonConverterFactory create() {
return create(new Gson());
}
public static GsonConverterFactory create(Gson gson) {
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
//'这个方法从名字就可以看出来,是用用来给ResponseBody转换成我们要的对象'
@Override
public Converter<ResponseBody, ?> responseBodyConverter(final Type type, Annotation[] annotations, Retrofit retrofit) {
Type newType = new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[] { type };
}
@Override
public Type getOwnerType() {
return null;
}
@Override
public Type getRawType() {
return HttpResult.class;
}
};
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(newType));
//'可以看到,用在Response的转换器是叫GsonResponseBodyConverter对象'
return new GsonResponseBodyConverter<>(adapter);
}
//'这个名字也可以看出来是把我们传入的对象转换成RequestBody,从而发起请求'
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations,
Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//'可以看到,用在Request的转换器是叫GsonRequestBodyConverter对象'
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
我们具体来看看GsonResponseBodyConverter
:
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public T convert(ResponseBody value) throws IOException {
//'根据传入的ResponseBody得到JsonReader'
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
//'很简单,就是GSON进行相关的JSON解析'
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
}
这里我们看到了既然解析部分是在这里,是不是我们可以做很多定制化操作,答案当然是Yes,比如我写了个自定义的GsonResponseBodyConverter来进行替换(下面的类就随便写写,大家可以根据自己的需求写自己的自定义转换器):
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, Object> {
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(TypeAdapter<T> adapter) {
this.adapter = adapter;
}
@Override
public Object convert(ResponseBody value) throws IOException {
try {
//'因为我统一的外层对象都是使用的HttpResult,我的代码是这么写的Observable<HttpResult<xxxBean>>'
HttpResult apiModel = (HttpResult) adapter.fromJson(value.charStream());
//'直接在这里就对统一处理操作'
if (apiModel.getCode().equals(CompanyHttpCode.TOKEN_NOT_EXIST)) {
throw new TokenNotExistException();
} else if (apiModel.getCode().equals(CompanyHttpCode.TOKEN_INVALID)) {
throw new TokenInvalidException();
} else if (!apiModel.getCode().equals(CompanyHttpCode.SUCCESS_CODE)) {
// 特定 API 的错误,在相应的 Subscriber 的 onError 的方法中进行处理
throw new ApiException();
} else if (apiModel.getCode().equals(CompanyHttpCode.SUCCESS_CODE) || apiModel.getCode().equals(CompanyHttpCode.SUCCESS_CODE_STR)) {
return apiModel;
}
} finally {
value.close();
}
return null;
}
}
好了,我们已经拿到了相应的Observable<xxxBean>
里面的xxxBean对象了,我们可以看到:
try {
//'我们前面讲过,通过这个方法转换的parseResponse(rawResponse);
把OkHttp3.Response转换成了Retrofit.Response<我们的bean> '
} catch (Throwable e) {
callFailure(e);
return;
}
try {
//'在转换成功后,我们就把具体的response重新通过回调函传回去给CallEnqueueObservable'
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
CallEnqueueObservable的onResponse方法:
@Override public void onResponse(Call<T> call, Response<T> response) {
if (disposed) return;
try {
//'我们可以看到,Observable调用了observerde的onNext方法把Retrofit.Reponse对象发送了出去'
observer.onNext(response);
......
......
......
}
可能有些人就会奇怪了,我们平常使用,明明拿到的就是具体的里面的xxxBean对象,而不是Response<xxxBean>
,那是因为上面我们提过的,我们的Observer被BodyObserver包了一层:
private static class BodyObserver<R> implements Observer<Response<R>> {
@Override public void onNext(Response<R> response) {
if (response.isSuccessful()) {
//'最终到我们的Observer的时候,就是Response里面包含了的我们写的xxxBean对象了。'
observer.onNext(response.body());
} else {
.....
.....
}
}
......
......
}
结语:
所以现在我们再来看代码,是不是已经就能懂中间到底做了什么操作。哈哈:
interface InfoApi{
@GET("userinfo.do")
Observable<UserBean> getInfo(@Query("name") String nameStr);
}
Retrofit retrofit = new Retrofit.Builder()
.client(new OkHttpClient())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://xxxx.com/")
.build();
retrofit.create(InfoApi.class)
.getInfo("青蛙要fly")
.subscribe(new ResourceObserver<UserBean>() {
@Override
public void onNext(UserBean userBean) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
然后再回头看这个图片,是不是也看得懂了:
不知不觉就写完了,哈哈,可能有些地方不详细或者是写的不好又或者是写错了。可以留言,我更希望的是能指出我哪里写错了,哈哈,这样我也可以纠正错误的知识。