关于Retrofit是啥,这里就很少解释了,仍是先来瞅下官网:java
而此次主要是了解它的底层动做机制,而在了解底层以前先来回顾一下官网的总体使用步骤:git
我们也以官网的这个例子为例,先从简单的使用开始逐步深刻,先新建一个工程:github
而后增长retrofit的build引用 ,以下:json
而后按官网的步骤,首先建立一个API接口,以下:api
我们以获取用户在github中的仓库为例,定义接口的API方法以下:数组
而后具体来调用一下,也如官网的描述同样:浏览器
而后此时并未发起HTTP请求,须要像okhttp那样调用一下这个方法,分同步和异步,固然这里得用异步喽,以下:缓存
而后增长访问网络的权限:网络
先来查看一下个人github的仓库:异步
而后运行一下:
成功了,其实这个接口返回的格式就是json,用浏览器能够访问看下结果:
接下来我们将结果打印成咱们看到的JSON格式同样,而我们目前成功返回的是一个RsponseBody对像,它是来自okhttp的,以下:
此时就须要注册一个转换器了,这里不细讲怎么用的,直接上结果,重点是经过简单的使用掌握其深层次的本质原理,也就是源码分析,下面来看怎么作这个转换:
那此时怎么写这个转换工厂呢,这时须要再加一个库,也就是gson的支持,关于gson是啥就里就很少说了,直接添加依赖以下:
此时就能够这么用了:
接下来则须要修改API接口了,由于咱们不想看到返回的ResonseBody对象,而想看到具体的JSON,从网站上返回的JSON能够看出其实就是一个JSON数组,因此返回的内容应该是一个List,因此修改一下:
而后里面的每一个对象则须要咱们手动定义出来,先假设这个对像类为Repo,以下:
接下来则定义该类:
而后再定义里面的字段,这里能够经过JSON自动转成Java的字段,能够用JsonFormat工具,以下:
而后将Json数组中的对象内容拷至其中:
接下来我们来修改一下返回值,以下:
而后运行:
ok,对于retrofit的简单用法就到此结束,重点是接下来分析它的源码:先从使用入口来进行分析的突破口,而使用入口就是它:
能把它分析明白了,那对于retrofit的核心原理也就清楚啦,因此点进去看下它的源码:
那此时就得看调用这个方法的对象是哪一个了,以下:
而这个API是我们定义的接口,也是抽象的。。
那此时就再得往前追溯了,得看它具体的对象:
若是知道了gitHubService的具体对象那么最终咱们就能够分析enqueue的具体实现了,因此定位其实现瞅一下:
这个方法是retrofit的核心,其实能够看到有动态代理的东东,因此如今就集中来分析一下该实现:
从字面意思来看是验证服务接口,看下究竟看了啥:
不重要,继续往下读:
这里是一个配置项的检查,表示是否要进行激进化的方法检查,具体就不细看了,不是核心,主要是对咱们写的api的方法合法性的检查,如:
若是开启了则会GitHubService一建立就会把全部的验证都作完了,很利于咱们的调试,很早就能够发现代码写得不对,可是!!不利于性能,大体知道就好了,继续往下看:
动态代理嘛,难道说retrofit的核心机制就是动态代理?其实确实是它,不过目前还不得而知,关于动态代理是啥这里就不过多解释了,j2se的基础,这里用伪代码来揭露其动态代码的本质,首先看第二个参数:
其实动态代理就是首先生成一个实现了该接口的对象,伪代码表示一下:
而后动态代理不是还有第三个参数InvocationHandler么?以下:
其实它就会传到动态生成的代理对象里面,而后在每一个具体方法实现中则会用到它来生成,伪代码以下:
若是说咱们在API接口中定义了多个方法,则在这个动态生成的对象中的实现也都是用invocationHandler来实现的,这就是动态代理的本质。
那接下来就把精力花在这个invoke方法的具体实现上了,只要分析清楚了它,那么就知道为啥咱们仅仅声明一个API接口retrofit就能够实现一个网络请求了,因此,研究一下invoke方法的具体实现:
而若是调用的是接口中的默认实现方法【这是Java8才有的】,直接也不作其它任何处理了,对于使用retrofit而言不可能有这种默认方法,因此能够略过这个判断细节,继续往下探究:
好晕呀,这三行中涉及到彻底陌生的ServiceMethod、OkHttpCall,彻底不明白,这里就涉及到一个读源码的小技巧了,对于都看不懂的状况下,先对涉及到的类都大至认识一下既可,不用深究,因此我们一个个先来大体瞅一下:
啥意思?首先得理解一下什么是adapter,这个在咱们listview的开发中必用的概念,仍是先看一下它词的本义:
也就是作转接用的,也就是能够猜想ServiceMethod的做用是:
而后此类的代码量太大,也无法继续往下看了,仍是返回到主调代码处继续了解其它的东东,继续看下它:
而后我们来看一下ServiceMethod是如何生成的,经过生成细节看是否能进对ServiceMethod有一个进一步的了解,以下:
而后再看一下build()方法的细节:
而后再经过构造来实例化:
很经典的Builder模式,不过整个构建对象的细节彻底看不懂,先暂且放着,等回过头按需再来查看,先来讲一下Builder模式,人人皆知,这里简单说一下它的好处,一般咱们用Builder模式一般会这样写:
那它有啥好处呢?对于Person中有字段是有初始化成本的,什么意思?好比咱们用正常的方式来初始化会这样写:
首先就在内存中有person对象了,接着再来修改一下性别:
而默认性别是女的,此句执行以后就须要在内存中将女姓给擦掉,而后用这个设置的男性来替代,这是有性能损耗的,接着再来修改年龄:
若是默认年龄是24,那此时内存中又得将24给擦掉而后再画一个31岁的人,再接下来:
默认人是走路的行为,此时又得内存进行擦除改掉用户的行为,因此说这种传统的方式是有性能损耗的,而Builder模式则在构建对象时没有提早生成内存,先生成一个配置清单,最终一块儿来构建对象,这是它的最大好处之一,另一个好处就是当参数较多的时候这样写层次也比较清晰,关于builder模式这里简单提一下,还得回到我们所关心的retrofit实现原理上来:
打开瞅下它是啥?
那不就是说:
因此此时我们能够看一下enqueue的具体实现:
先跳出这个实现细节,总的来回顾一下:
因此点进入再看最后一行的细节:
没办法,还得硬着头皮点进去瞅下:
那看不懂呀,怎么整,目前咱们要了解的这三行代码,前两行大体猜到了一些意思,而最后一行彻底不晓得其内部的细节,那接下来就从头来细看一下,看是否经过细看能发现一些线索:
这个以前稍加看过,里在就是维护了一个缓存,不过这里仍是要看一下ServiceMethod的建立过程:
其中第一句看到了一个以前的疑问:
其中这上callAdapter是一个接口,因此此时不就解惑了么,因此看一下callAdapter是如何建立的?
跟进去:
再往下跟:
接下来就得看一下这段代码的实现了,先来瞅一下callAdapterFactories对象:
因此看一下它的调用,其实就是在build()方法中,如咱们在Activity写的:
因此此时再看一下callAdapterFactories的建立来源:
而后就得看下一句了:
因此。。得看一下"platform.defaultCallAdapterFactory(callbackExecutor)"的细节:
如:
其中咱们能够看到其实现中用到了一个“callbackExecutor”,经过它的执行而后再处理的回调:
因此得看一下callBackExecutor是如何传递进来的,此时就又得回调Retrofit.build()方法来了:
而后再进一步跟一下此callbackExecutor的建立细节:
那。。原来咱们看到的calladapter的做用是进行线程的转换哦,那咱们继续回到ServiceMethod.build()方法分析:
拿咱们定义的API接口方法来讲就是指的:
接下来往下:
继续往下
这不就是指么:
好,再继续往下:
另外有一个细节须要注意retrofit会对咱们写的注解的正确性作验证,会让咱们更加规范的使用okhttp,好比multipart须要配合part来使用等,好对于ServiceMethod的build()方法能够发现其实就是对咱们定义的API方法进行了解析并存下来,而后再实例化它:
至此,我们要想分析关键的第一句代码就完全搞清楚其做用了,回顾一下:
好,接下来再分析核心的第二句代码,好比好理解:
接着再来看第三句代码,其实经过上面的分析也晓得其做用了,挼一下:
而后此时得回顾一下callAdpater是如何建立出来的:
而后此方法的调用是在调用build()时进行的,以下:
因此最终调用adapt()方法的实际上是ExecutorCallAdapterFactory里面的了,以下:
也就是最终retrofit动态生成的对像在调用它里面的getRepos()方法返回的是ExecutorCallbackCall对像,以下:
因此接下来咱们再来分析最初咱们分析不动的方法就顺其天然啦,也就是:
那就是直接调用ExecutorCallbackCall.enqueue()方法,以下:
而代理的call是在咱们代理对像方法执行时动态建立的,以下:
因此最终就会转到OkHttpCall.enqueue()方法来,以下:
其中仍是利用了ServiceMethod来对以前解析的东东来转换成了okhttp的call,以下:
而后再利用Okhttp的Call进行异步请求,以下:
@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 { call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> 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(); } } }); }
其中回调是先对OkHttp的Response进行解析,解析成Retrofit的Response:
而后这个parseResponse()方法就能够体现出它与http的关系了,就是用了http的知识来编写的,大体瞅一下:
其中从okhttp的reponse转成retrofit的response最终还用到了converter了,以下:
最后还有一个知识就是retrofit如何集成rxjava,首先得集成一下rxjava,以下:
而后此时须要在增长一个calladapter,以下:
此时咱们的API定义返回就不用返回Call对像了,而是能够返回一个Observable,以下:
而后就能够用rxjava的那一套来进行接口请求及返回处理了,Retrofit是能够支持多个Adapter的,瞅一下:
其中咱们知道Retrofit默认的Adapter为CallAdapter,是能够将ResponseBody转换成一个Call对象,以下:
其具体实现是:
并达到一个切换线程的做用。
而此时加了一个Rxjava的CallAdapter,以下:
因此咱们在api能够为:
到此!!已经完整将Retrofit的整个核心机制分析完了,对于以后在实际工做中用Retrofit也更加踏实了~~说实话仍是挺复杂的。