内容简介:介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看,最好可以指出我的错误,让我也能纠正。
哈哈,其实写的还是很水,各位原谅我O(∩_∩)O。
介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看,最好可以指出我的错误,让我也能纠正。
1.讲解相关的整个网络体系结构:
2.讲解相关网络的重要知识点,比如很多人都听过相关网络方面的名词,但是仅限于听过而已,什么tcp ,udp ,socket ,websocket, http ,https ,然后webservice是啥,跟websocket很像,socket和websocket啥关系长的也很像,session,token,cookie又是啥。
相关网络知识点小结- socket/websocket/webservice
相关网络知识点小结- cookie/session/token(待写)
3.相关的第三方框架的源码解析,毕竟现在面试个大点的公司,okhttp和retrofit源码是必问的。
正文
因为我平时使用的都是Rxjava2 + Retrofit ,所以我相关的源码解析都是配合RxJava来的,而不是Call返回对象。
读本文的我推荐大家最好对OKHttp源码有所了解,再来看本文,因为Retrofit内部还是通过OkHttp发出网络请求。大家也可以看我前面写的: Android技能树 — 网络小结之 OkHttp超超超超超超超详细解析 ,同时本文不会再去教大家Retrofit的基础使用,如果要看一些简单使用,可以看下面的一些推荐博客:
Android Retrofit 2.0 的详细 使用攻略(含实例讲解)
Android:Retrofit 结合 RxJava的优雅使用(含实例教程)
我们先上一张别的大佬博客中的一张图:
这个图画的很好,但是这个图更多的是从大局观来看,所以如果对于源码不是有一些基础了解的话,看这个图很容易就忘记。
看过我的Okhttp源码分析的文章: Android技能树 — 网络小结之 OkHttp超超超超超超超详细解析 ,我们文中的Okhttp流程图就是跟着源码一步步来画的。我更喜欢是跟着源码一步步来画流程图(PS:其实是我水平太差了,无法一下子总结处第三方库的各种 设计模式 的使用),所以Retrofit我也画了下面这个图:
而等会我们分析完这个跟着源码分析的流程图后,再回头看上面的别人博客中的总结的Retrofit结构图,就会很简单了。
首先我们来确定总体大纲:
我们知道我们的目标是要发起一次网络请求,他有这么几步:
- 告诉它一些基本信息,比如url地址,网络请求方式(get、post、...等),请求参数值。然后拼装成一个标准的网络Request请求的格式发出去。所以这里有二步动作:1.先解析我们写的参数,2.再解析完后拼装成标准的网络Request请求格式
- 发出请求后,接收到了后台的Response返回结果,我们要把Resonse转换成我们想要的返回结果。但是我们写的想要的返回结果又有二大关键地方,我们平常的返回结果可能是
X <Y>
,我们先来看外面的X的类型
,比如我们常见的返回结果是Call<Y> 和 Observable<Y>
,所以我们在转换的时候一是要考虑最外面的那个返回类型的转换。另外一个是Y的类型
,也就是里面我们具体写的Bean对象,比如我们直接返回字符串,那可能就是Observable<String>
,又或者是自己定义的xxxBean对象,那就是Observable<xxxBean>
。所以我们要有二类转换:1.外层的结果类型,比如Call或者Observable等,2.是泛型里面填的具体的Bean对象类型
所以我们总结起来就需要四步:
- 解析并拿到我们写的一些参数(url,请求方式(post/get),请求参数......)
- 根据我们写的参数,拼成一个网络请求Request,去帮我们发起请求。
- Response如何转换成Call或者Observable等返回类型,和第3步中的Bean对象拼成了Call《Bean》或者Observable《Bean》
- Response如何转换成我们所需要的具体的Bean对象。
没错,下次别人问你,你就心里有数了,到底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的这几个方法,可以看下面的相关链接:
java.lang.reflect.Method.getGenericParameterTypes()方法示例.
使用反射获得参数列表里的注解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() { } }); 复制代码
然后再回头看这个图片,是不是也看得懂了:
不知不觉就写完了,哈哈,可能有些地方不详细或者是写的不好又或者是写错了。可以留言,我更希望的是能指出我哪里写错了,哈哈,这样我也可以纠正错误的知识。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
加密与解密(第4版)
段钢 / 电子工业出版社 / 2018-10-1 / 198
《加密与解密(第4版)》以加密与解密为切入点,讲述了软件安全领域的基础知识和技能,如调试技能、逆向分析、加密保护、外壳开发、虚拟机设计等。这些知识彼此联系,读者在掌握这些内容之后,很容易就能在漏洞分析、安全编程、病毒分析、软件保护等领域进行扩展。从就业的角度来说,掌握加密与解密的相关技术,可以提高自身的竞争能力;从个人成长的角度来说,研究软件安全技术有助于掌握一些系统底层知识,是提升职业技能的重要......一起来看看 《加密与解密(第4版)》 这本书的介绍吧!