美文网首页Android技术知识Android开发
从源码的角度分析Retrofit

从源码的角度分析Retrofit

作者: 双鱼大猫 | 来源:发表于2016-11-12 17:57 被阅读57次

初识Retrofit,我觉得很神奇,体现在一下两点:

第一:仅凭注解和接口便可以执行网络请求。

public interface GithubService{

@GET("users/{username}")

Call getUser(@Path("username") String username);

}

第二:接口的方法的返回值变换无穷。

无论你是用默认的方式,或者是RxJava, 无论是在Java或者是在Android中调用,Retrofit均可以满足,体现在接口的返回值,如下代码:

public interface GithubService{

//默认方式

Call getUserByDefault(@Path("username") String username);

//RxJava方式

Obserable getUserByRxJava(@Path("username" ) String username);

}

我一开始接触到这两种用法的时候,觉得百思得不起姐啊!后来实在按捺不住内心的好奇心,于是,便开始了阅读源码之旅。

寻找接口的实现类

对于我们的第一个问题,首先我们来看看GithubService接口是如何调用的:

Retrofit retrofit = new Retrofit.Builder()

.baseUrl("Http://api.github.com/")

.build();

GitHubService service = retrofit.create(GithubService.class);

Call call = githubService.getUser("geniusmart");

代码细一看,又让我产生了一些疑问, 首先,GithubService本身是一个接口,并调用了getUser()方法获得了返回值,那么问题来了:

1、GithubService 是由我们定义的接口,但是我们并没有定义实现类,实现类到底在哪里呢?

2、既然我们没有定义实现类,那么大胆假设实现类是Retrofit框架提供的,对于框架而言,该接口是开发者自定义的,框架无法做到未卜先知,那么,Retrofitu又是如何做到的呢?

以上两个问题可以总结为:框架如何动态生成GithubService的实现类?

答案也不难猜  —— 动态代理模式 (对动态代理有疑问的同学,可以先看下我的另外一篇文章《Java动态代理初步认识》)。

接下来验证我们的猜想,GithunService究竟是从哪里来的呢,请看代码:

GithubService service = retrofit.create(GithubService.class);

查看 create() 的源码,就一目了然了:

通过JDK实现动态代理

这个方法生成返回GithubService的动态代理对象,在执行接口的每个方法时,实际执行的是invoke(),而该方法里的逻辑便是此框架的主体流程,代码如下:

public Object invoke(Object proxy, Method method, Object... args){//1.负责注解的解析

ServiceMethod serviceMethod = loadServiceMethod(method);

//2.负责与OKHttp3的对接,处理同步和异步发送网络请求

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

//3.适配 okHttpCall

return serviceMethod.callAdapter.adapt(okHttpCall);

}

这个方法里,做了三件事情:

1、解析方法的注释,比如get/post、url 、Headers 等,解析的结果存放于ServiceMethod对象中。

2、创建OkHttpCall,该对象负责与OkHttp3对接,处理同步或者异步的网络请求。

3.适配 okHttpCall

变幻无穷的适配

首先来回顾下上文提到的第二个疑问,同样是获取用户信息的网络请求,可以返回Call,这是如何做到的?

在上面提到,invoke()做的第三件事情便是获取返回值,代码如下:

return serviceMethod.callAdapter.adapt(okHttpCall);

其中,adapt是适配的意思,其目的是变废为宝,将指定的输入类型适配成实际需要类型,来查看它的源码:

public interface CallAdapter{

T adapt(Call call);

}

我们重点关注下adapt的输入和输入,这里的设计非常大胆,输入的是被约束类型,即Call类型,而输出为泛型T,也就是输出是没有任何约束的,如此一来,扩展性极强,可以指定任何的类型。

接下来的问题是:

1、adapt由哪个对象触发,即CallAdapter的具体实现是什么?

2、输入类型Call的具体实现是什么?

3、输出类型T的具体实现是什么?

这里直接给出答案,如下两图:

默认方式的适配

RxJava方式的适配

通过上面两图,可以看到,输入对象是固定的,即OkHttpCall对象,网络请求实际上便是由该对象发起的。

默认方式的输出对象是ExecutorCallbackCall,它持有OkHttpCall对象,指定了网络请求执行结束后的回调函数在UI线程中执行。

RxJava方式的输出对象是Observable,持有该对象便具备函数式编程的能力。

adapt()的调用者——适配器CallAdapter是动态配置的,默认方式无需配置,如果使用RxJava,则需要配置适配器的工厂对象,如下代码:

Retrofit retrofit = new Retrofit.Builder()

.baseUrl(BASE_URL)

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

.build();

这样设计简直是解耦得一塌糊涂,我们可以任意变换调用方式,也可以任意扩展CallAdapter来定义新的调用方式,而框架无需做任何调整。比如JakeWharton前几天开源的RxJava2的适配——retrofit2-rxjava2-adapter,比如针对Google函数式编程库 Agera的适配——retrofit-agera-call-adapter,简直OCP得一塌糊涂。

总结

动态代理、适配是Retrofit的核心,理解清楚这两点,再去梳理框架的其他细节,方可事半功倍。除此之外,框架内部使用了大量的Builder模式和Factory模式,这两个模式使得创建对象和获取对象更有条理,更清晰易懂。值得一提的是,这个框架配备了完整的单元测试用例,非常值得我们学习。

参考文章

http://square.github.io/retrofit/

https://github.com/square/retrofit

更多内容请关注我的个人微信公众号:前端开发技术栈

相关文章

  • 从源码的角度分析Retrofit

    初识Retrofit,我觉得很神奇,体现在一下两点: 第一:仅凭注解和接口便可以执行网络请求。 public in...

  • retrofit 源码分析

    retrofit 源码分析 retrofit 源码分析源码执行流程new Retrofit.Builder().b...

  • Retrofit流程+源码分析

    前言 前一篇分析了OkHttp的源码和流程,这一篇依然从Retrofit的使用角度并结合源码来分析,当然Retro...

  • Retrofit源码分析

    Retrofit 源码分析 Retrofit地址 Retrofit分析-经典设计模式案例 RxAndroid Gi...

  • 【Retrofit2进阶】---启示、思想

    前言 之前的文章 从源码角度看Retrofit2实现原理 已经介绍过Retrofit2源码和原理了,本文试图站在更...

  • okhttp3 源码分析

    在上一篇 Retrofit 学习第三弹—源码分析篇 分析了 Retrofit 的源码,分析到请求 Call 位置,...

  • Retrofit源码分析(一)

    这篇主要分析一下retrofit源码,分析的切入点就是从使用流程开始。 使用方式 首先是创建Retrofit实例,...

  • Retrofit源码解析

    0.前言 终于到了源码分析系列的Retrofit篇了。有关retrofit源码分析的文章网上有很多,但是都是属于旧...

  • Retrofit源码分析一 概览

    Retrofit源码分析一 概览 Retrofit的本质和与Okhttp的关系​ 说到Retrofit,免不...

  • Retrofit2源码分析

    Retrofit源码分析基于2.4.0。 关于Retrofit的基本使用可以参照 Retrofit官网。 Retr...

网友评论

    本文标题:从源码的角度分析Retrofit

    本文链接:https://www.haomeiwen.com/subject/liuqpttx.html