Android开发Retrofit源码分析


项目结构 把源码 clone 下来 , 可以看到 retrofit 整体结构如下
图 http包目录下就是一些http协议常用接口 , 比如 请求方法 url , 请求体, 请求行 之类的
retrofit 使用 把retrofit使用作为分析的切入口吧 , retrofit单元测试使用如下
public final class basiccalltest {@rule public final mockwebserver server = new mockwebserver();interface service {@get("/") call<responsebody> getbody();}@test public void responsebody() throws ioexception {retrofit retrofit = new retrofit.builder().baseurl(server.url("/")).build();service example = retrofit.create(service.class);server.enqueue(new mockresponse().setbody("1234"));response<responsebody> response = example.getbody().execute();assertequals("1234", response.body().string());}}retrofit 构建 , 以构建者模式构建出retrofit
可以看到builer可以配置baseurl , 回调线程池 , 还有一些适配器的工厂 , 这些适配器的作用后面说
retrofit #create 从create 方法开始分析 , 跟进看下create 方法
public <t> t create(final class<t> service) {validateserviceinterface(service);return (t)proxy.newproxyinstance(service.getclassloader(),new class<?>[] {service},new invocationhandler() {private final object[] emptyargs = new object[0];@overridepublic @nullable object invoke(object proxy, method method, @nullable 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);}args = args != null ? args : emptyargs;platform platform = platform.get();return platform.isdefaultmethod(method)? platform.invokedefaultmethod(method, service, proxy, args): loadservicemethod(method).invoke(args);}});}service 是请求的接口的class , 动态代理只能是接口 , 所以validateserviceinterface 先验证是不是接口 , 不是接口则抛异常 。
method.getdeclaringclass() 获取声明类的class 。
比如 a类 有个method , method.getdeclaringclass() 返回为a.class , 如果method声明类是object.class 则直接method.invoke , 往下执行毫无意义 。
platform#get()会根据当前平台获取platform。
有点类似状态模式思想 , 根据当前的平台选择合适的子类
public boolean isdefaultmethod(method method) {return method.isdefault();}isdefault , 在接口类型中以default关键字声明 则返回true, 比如
interface interfacewithdefault {void firstmethod();default void newmethod() {system.out.println("newmethod");}}所以此处会返回 false 接着调用 loadservicemethod 。

servicemethod #parseannotations 跟进servicemethod #parseannotations
static <t> servicemethod<t> parseannotations(retrofit retrofit, method method) {requestfactory requestfactory = requestfactory.parseannotations(retrofit, method);return httpservicemethod.parseannotations(retrofit, method, requestfactory);}根据当前的方法信息构建出requestfactory , 然后把具体实现细节交给httpservicemethod 处理 , httpservicemethod 继承自servicemethod , 有三个子类。
我们在api.class定义的方法 , 解析并不是由httpservicemethod 完成 , 而是由requestfactory去处理的 , 比如解析方法的注解 。
更多的解析方法如下
方法解析的细节就不说了 , 继续看requestfactory 这个类 , 这个类的作用难道就是负责方法信息的解析 , 感觉和名字不太符合 , requestfactory 顾名思义应该是用来构建request的工厂 , 果不其然内部还有个 create 方法 , 用来构建okhttp3.request的
//requestfactory #createokhttp3.request create(object[] args) throws ioexception {return requestbuilder.get().tag(invocation.class, new invocation(method, argumentlist)).build();}就只有这一个create方法 , 难道retrofit 就只能使用okhttp来负责网络请求 ? 答案是肯定的 , 从最开始的 loadservicemethod(method).invoke(args)也可以看出 , 方法里面只构建出okhttpcall 没提供api可以让我们切换到其他的网络请求库 。
但是 , call 又抽象成接口的形式 ,如下, 这么做的目的可能是以后便于框架的维护
沿途风景再美丽 , 也要回到主线路 , 继续分析 httpservicemethod#parseannotations
httpservicemethod#parseannotations 这个方法太长 , 贴关键代码吧
static <responset, returnt> httpservicemethod<responset, returnt> parseannotations(retrofit retrofit, method method, requestfactory requestfactory) {boolean iskotlinsuspendfunction = requestfactory.iskotlinsuspendfunction;boolean continuationwantsresponse = false;boolean continuationbodynullable = false;boolean continuationisunit = false;annotation[] annotations = method.getannotations();type adaptertype;if (iskotlinsuspendfunction) {type[] parametertypes = method.getgenericparametertypes();type responsetype =utils.getparameterlowerbound(0, (parameterizedtype) parametertypes[parametertypes.length - 1]);if (getrawtype(responsetype) == response.class && responsetype instanceof parameterizedtype) {continuationwantsresponse = true;}} else {//非kt 协程情况adaptertype = method.getgenericreturntype();}calladapter<responset, returnt> calladapter =createcalladapter(retrofit, method, adaptertype, annotations);type responsetype = calladapter.responsetype();converter<responsebody, responset> responseconverter =createresponseconverter(retrofit, method, responsetype);okhttp3.call.factory callfactory = retrofit.callfactory;if (!iskotlinsuspendfunction) {//非kt 协程情况return new calladapted<>(requestfactory, callfactory, responseconverter, calladapter);} else if (continuationwantsresponse) {return (httpservicemethod<responset, returnt>)new suspendforresponse<>(requestfactory,callfactory,responseconverter,(calladapter<responset, call<responset>>) calladapter);} else {return (httpservicemethod<responset, returnt>)new suspendforbody<>(requestfactory,callfactory,responseconverter,(calladapter<responset, call<responset>>) calladapter,continuationbodynullable,continuationisunit);}}构建出httpservicemethod分两种情况 :

  • kotlin 协程情况
  • 非kotlin 协程情况

第二种 非kotlin协程情况 第一种情况稍许复杂 , 先分析第二种
adaptertype = method.getgenericreturntype();
@get("/") call<responsebody> getbody();如果是上面代码 , method.getgenericreturntype() = call , 然后根据方法的返回值类型 / 方法注解信息 , 构建出calladapter。
createcalladapter() 方法会使用 calladapter.factory 构建calladapter , 因为初始化retrofit的时候没有配置calladapter.factory , 所以会使用默认的defaultcalladapterfactory 。
最终会进入defaultcalladapterfactory#get。
defaultcalladapterfactory#get 这个方法作用就是返回calladapter , 修改下源码加入两个打印 。
public @nullable calladapter<?, ?> get(type returntype, annotation[] annotations, retrofit retrofit) {final type responsetype = utils.getparameterupperbound(0, (parameterizedtype) returntype);system.out.println("tag" + " ->" + "returntype = " +getrawtype(returntype) .getsimplename());system.out.println("tag" + " ->" + "responsetype = " +getrawtype(responsetype) .getsimplename());return new calladapter<object, call<?>>() {@overridepublic type responsetype() {return responsetype;}@overridepublic call<object> adapt(call<object> call) {return executor == null ? call : new executorcallbackcall<>(executor, call);}};}运行可以看到以下打印信息
returntype = call ,responsetype =responsebody。
【Android开发Retrofit源码分析】总结一下 , returntype就是方法返回值 , responsetype 就是方法返回值上的泛型 defaultcalladapterfactory会根据平台环境去构建 。
以android24分析 , defaultcalladapterfactory(executor callbackexecutor) , 构造方法中 , 线程池为主线程池 , 在retrofit初始化的时候添加到 到calladapterfactories 集合中 。
至此 , calladapterfactory 和 calladapter 分析完了 , 总结下就是给call (retrofit内存只有okhttpcall 作为唯一实现类)做适配 , 让其可以在 rxjava / 协程 等各个环境中使用 call 。
非kt 协程情况下 , parseannotations 方法最终返回的是将requestfactory , callfactory , responseconverter, calladapter 封装好的calladapted 对象 。
再次回到梦开始的地方retrofit#create 方法 , loadservicemethod获取的servicemethod最终实现类为calladapted , 获取之后会调用invoke方法 , invoke是一个final方法 , 里面构建了okhttpcall , 然后调用了adapt方法 , adapt中调用了calladapter.adapt(call) 。
@overrideprotected returnt adapt(call&lt;responset&gt; call, object[] args) {return calladapter.adapt(call);}这里的returnt 就是executorcallbackcall<>(executor, call) 对象 , 所以 example.getbody().execute() 就是调用executorcallbackcall#execute方法
//executorcallbackcall#execute public response<t> execute() throws ioexception {return delegate.execute();}delegate为okhttpcall , 所以就调用到okhttpcallcall#execute方法 , 这里就转给okhttp去请求网络加载数据了 , 代码就不贴了 , 我们看下网络请求之后 , 数据response 的处理 , 关键代码okhttpcall#parseresponse 。
response<t> parseresponse(okhttp3.response rawresponse) throws ioexception {responsebody rawbody = rawresponse.body();exceptioncatchingresponsebody catchingbody = new exceptioncatchingresponsebody(rawbody);try {t body = responseconverter.convert(catchingbody);return response.success(body, rawresponse);}}responseconverter 在 httpservicemethod#parseannotations 方法中获取 , 回应数据转换器 , 把数据转换成我们可以直接使用的对象 , 比如我们常用的 gsonconverterfactory 。
最后把转换好之后的数据 , 封装成response对象返回 。
response.body()就是responseconverter 转换后的数据 来张大致流程图感受下吧

第一种 kotlin协程情况 其实大致流程第二种情况分析的差不多了 , 接下来分析下retrofit对于kotlin的特殊处理吧 。
if (utils.getrawtype(parametertype) == continuation.class) {iskotlinsuspendfunction = true;return null;}协程挂起方法 , 第一个参数为continuation , 所以判断是不是挂起方法也很简单 , 根据responsetype 去构建协程专用的httpservicemethod , 主要有两类 。
  • suspendforresponse , 对应type为continuation<response>
  • suspendforbody , 对应type为continuation
这里看下 suspendforbody 实现 , 套娃情况就不分析了 。
如果是这样使用 , 最终会调到suspendforbody #adapt 。
@overrideprotected object adapt(call<responset> call, object[] args) {call = calladapter.adapt(call);continuation<responset> continuation = (continuation<responset>) args[args.length - 1];try {//去掉干扰代码 , 仅保留这个return kotlinextensions.awaitnullable(call, continuation);}}这个地方就很关键了 , java 直接调kotlin 协程 suspend 方法 。
kotlinextensions.awaitnullable 会调到kotlinextensions#await方法 。
retrofit与协程适配的细节都在 kotlinextensions这个类里 。
进入await , 可以看到使用suspendcancellablecoroutine把回调装换成协程 。
@jvmname("awaitnullable")suspend fun <t : any> call<t?>.await(): t? {return suspendcancellablecoroutine { continuation ->continuation.invokeoncancellation {cancel()}enqueue(object : callback<t?> {override fun onresponse(call: call<t?>, response: response<t?>) {if (response.issuccessful) {continuation.resume(response.body())} else {continuation.resumewithexception(httpexception(response))}}override fun onfailure(call: call<t?>, t: throwable) {continuation.resumewithexception(t)}})}}其实内部也是调用 okhttp call.enqueue() , 只不过是用suspendcancellablecoroutine给协程做了一层包装处理
通过 suspendcancellablecoroutine包装之后使用就很简单了 。
globalscope.launch {try {val result = xxxapi.getxxx()} catch (exception: exception) {}}
总结 call 这个接口用于与网络请求库做适配 , 比如okhttp 。
calladapter 用于retrofit 与各种环境搭配使用做适配 , 比如rxjava / 协程 / java 。
converter 用于将请求结果转换实体类bean 或者其他 。
用到的设计模式有: 动态代理/静态代理 / 构建者 / 工厂 / 适配器 / 状态 等 。
以上就是android开发retrofit源码分析的详细内容 , 更多关于android retrofit源码分析的资料请关注www.887551.com其它相关文章!
-- 展开阅读全文 --

    推荐阅读