博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Retrofit2源码解析——网络调用流程(下)
阅读量:7168 次
发布时间:2019-06-29

本文共 6790 字,大约阅读时间需要 22 分钟。

Retrofit2源码解析系列

本文基于Retrofit2的2.4.0版本

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

上次我们分析到网络请求是通过OkHttpCall类来完成的,下面我们就来分析下OkHttpCall类。

final class OkHttpCall
implements Call
{ ... @Override public void enqueue(final Callback
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 { //调用createRawCall创建OkHttp3的Call call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } ... call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response
response; try { //解析返回的结果 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(); } } }); } ...}

OkHttpCall的enqueue方法主要干了2件事,一个是创建OkHttp3的Call用于执行网络请求;另一个是解析返回的结果并回调。下面我们来看看创建OkHttp3的Call的过程

//OkHttpCall.classprivate okhttp3.Call createRawCall() throws IOException {    okhttp3.Call call = serviceMethod.toCall(args);    if (call == null) {        throw new NullPointerException("Call.Factory returned null.");    }    return call;}

可以发现是通过serviceMethod的toCall方法来创建的

//ServiceMethod.classokhttp3.Call toCall(@Nullable Object... args) throws IOException {    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,            contentType, hasBody, isFormEncoded, isMultipart);    ...    for (int p = 0; p < argumentCount; p++) {        handlers[p].apply(requestBuilder, args[p]);    }    //最后调用OkHttpClient的newCall方法返回Call    return callFactory.newCall(requestBuilder.build());}

ServiceMethod的toCall方法也是通过OkHttpClient的newCall方法来返回Call的。

在我们通过OkHttpClient请求得到结果后,我们还需要将返回的结果Response解析成我们接口需要的实体类型,这就需要用到我们在创建Retrofit时设置的ConverterFactory了,比如GsonConverterFactory。

//OkHttpCall.classResponse
parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); ... ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { //通过serviceMethod的toResponse方法解析 T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { catchingBody.throwIfCaught(); throw e; }}

OkHttpCall的parseResponse方法调用的是serviceMethod的toResponse方法来解析返回的结果。

//ServiceMethod.classR toResponse(ResponseBody body) throws IOException {    return responseConverter.convert(body);}

在ServiceMethod中最后调用responseConverter的convert方法来转换返回的结果。这个responseConverter和上面分析的CallAdapter的确定过程一样,也是在ServiceMethod的build方法中,通过调用retrofit的requestBodyConverter方法遍历我们传入的ConverterFactory,直到找到合适的。

//Retrofit.classpublic 
Converter
requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations) { return nextRequestBodyConverter(null, type, parameterAnnotations, methodAnnotations);}public
Converter
nextRequestBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations) { ... int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) { Converter.Factory factory = converterFactories.get(i); Converter
converter = factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this); if (converter != null) { //noinspection unchecked return (Converter
) converter; } } ...}

需要注意的是在创建Retrofit时默认添加了一个BuiltInConverters,这个是Retrofit为我们提供一个默认的responseConverter,它主要处理的是返回类型是ResponseBody和Void的情况。

final class BuiltInConverters extends Converter.Factory {    @Override    public Converter
responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { if (type == ResponseBody.class) { return Utils.isAnnotationPresent(annotations, Streaming.class) ? StreamingResponseBodyConverter.INSTANCE : BufferingResponseBodyConverter.INSTANCE; } if (type == Void.class) { return VoidResponseBodyConverter.INSTANCE; } return null; } ...}

因为我们一般返回值类型都是具体的实体类型,所以我们需要添加自己的responseConverter,一般也就是GsonConverterFactory了。

至此,网络调用的后半部分流程也清楚了:

我们调用Call对象的enqueue方法发起异步请求时,实际上调用的是OkHttpCall对应的enqueue方法。OkHttpCall会先调用ServiceMethod类的toCall方法利用OkHttpClient的newCall方法创建OkHttp3的call对象,然后利用这个call对象执行具体的网络请求。在网络请求返回成功以后会调用ServiceMethod类的toResponse方法利用我们设置的responseConverter将返回结果转换成我们需要的类型,然后通过我们设置的回调或是默认的回调方法,将结果回调回主线程,从而完成整个请求过程。

总结

Retrofit2的网络调用的整个流程我们已经分析完了。通过这次分析,我们可以看到Retrofit2中最主要的就是3个类:Retrofit、ServiceMethod和OkHttpCall。这三个类指责明确,相互配合共同完成整个网络调用的流程。

(1)Retrofit负责供外部初始化和定制,保存CallAdapter的列表和ResponseConverterFactory列表。

(2)ServiceMethod对应每一个接口方法的信息,包括解析注解和参数等,同时它也是连接Retrofit和OkHttpCall的桥梁。ServiceMethod中保存着当前接口对应方法所需要的CallAdapter和ResponseConverter。利用CallAdapter将OkHttpCall转换成接口需要的类型,供接口调用。利用toResponse方法让OkHttpCall调用ResponseConverter解析网络请求返回的结果。

(3)OkHttpCall则是用来执行具体网络请求。Retrofit2没有直接使用OkHttp3的Call接口,而是有自己的Call接口。在OkHttpCall内部通过组合的方法持有OkHttp3的Call接口,并通过ServiceMethod的toCall方法得到OkHttp3的call来进行网络请求,减少对OkHttp3的耦合。


欢迎关注我的微信公众号,和我一起每天进步一点点!

AntDream

转载地址:http://hoqwm.baihongyu.com/

你可能感兴趣的文章
『中级篇』容器的技术概述(二)
查看>>
Apache awstats安装报错解决过程适合初学者
查看>>
Vsftp安装及配置虚拟用户
查看>>
JVM内存区域
查看>>
DNS的视图功能的简单配置。
查看>>
linux和windows互传文件/用户配置文件和密码配置文件/用户组管理/用户管理
查看>>
通过javascript把图片转化为字符画
查看>>
OpenJPA 一些难搞的查询
查看>>
设置button的样式,使得按钮的图片在上面,文字在图片的下面
查看>>
MySQL之函数、存储过程和触发器
查看>>
完整版的OpenLDAP搭建全过程
查看>>
java反射学习总结
查看>>
104. ftl 小数位处理
查看>>
云计算自动化平台HashiCorp获1亿美元D轮融资!
查看>>
防******
查看>>
python通过线程实现定时器timer的源码
查看>>
联通5G终端外场实测:最大下载速率曝光!
查看>>
MySQL CPU占用超过100%
查看>>
IT兄弟连 JavaWeb教程 jQuery对AJAX的支持经典案例
查看>>
Hello –Test Windows Live Write
查看>>