对项目的基本介绍
1.整个框架主要是给MVVM框架使用的,自己写完interface接口后,通过自定义的注解就能自动生成接口方法
2.用Kotlin的Flow去代替Rxjava,因为我发现RxJava功能很强大,但是大家都只是在Http层面使用了一下,既然要用Kotlin里面就已经有Flow,那我还不如少添加一个库
3.通过jetpack的Room数据库实现网络请求的存储,缓存策略也用过注解去完成。
4.发起的网络请求是与宿主生命周期绑定的,在网络请求回来之前,宿主已经销毁的话,网络请求也会中断的
基本使用方法
1.先定义接口类
和Retrofit一样,需要定义一个接口类
其中@AutoApi
,@AutoFlowApi
,@NetStrategy
是自定义的注解,后面会介绍到。
![](https://img.haomeiwen.com/i12417772/d14343a56cda7c9b.png)
2.要先编译,会在你的接口类的文件夹下生成一个xxxRepository.class
这是通过注解自动生成的文件,使用了kotlinpoet
并且这里apiService就是通过Retrofit拿到的接口代理
![](https://img.haomeiwen.com/i12417772/2e17481fd9ba1061.png)
3.在viewmodel拿到对应Repository类的方法
![](https://img.haomeiwen.com/i12417772/b419f1f347be1052.png)
4.在对应地方通过viewmodel调用
调用接口,传入对应参数
![](https://img.haomeiwen.com/i12417772/8c368e8954281bea.png)
在合适的地方观察
![](https://img.haomeiwen.com/i12417772/26e6b7151a79e506.png)
Retrofit的封装
上面说到在Repository类的apiService就是通过Retrofit拿到的接口代理类。
所以先进去看看apiService好了
可以看到apiService是BaseRepository的变量
而我们生成的Repository都是继承BaseRepository的
![](https://img.haomeiwen.com/i12417772/4a2368a3a8523c46.png)
当我们调ConfigRepository类中的方法时候,就会将ConfigRepository
传入findNeedType
![](https://img.haomeiwen.com/i12417772/26e10271a7ba1860.png)
而findNeedType
方法就会将ConfigRepository
对应的ConfigService
得到并且返回出去
![](https://img.haomeiwen.com/i12417772/01dab984a7c3f8da.png)
所以apiService就相当于这样,好像有点Retrofit的create方法的样子了
var apiService: T = HttpProvider.defaultCreate(ConfigService) as Class<out T>)
我们继续进入HttpProvider.defaultCreate
可以看到newRetrofit()
,并且传入了一个HttpConfig,看到这个名字就知道这是Http的配置
接着是newCreate(),接收了我们的接口service类
![](https://img.haomeiwen.com/i12417772/3362f49183dec335.png)
首先看看newRetrofit方法
这几行代码就是创建了一个Retrofit对象并且保存起来,最后返回出去。
但是他是怎么和HttpConfig联系起来的呢?
![](https://img.haomeiwen.com/i12417772/4ce49971ee191b61.png)
我们可以看到这里将生成的Retrofit.Builder()传给了HttpConfig的方法build里
,我们进去看一看
![](https://img.haomeiwen.com/i12417772/6158c872845f5cff.png)
可以看到这里就是我们再熟悉不过的Retrofit的配置环节
![](https://img.haomeiwen.com/i12417772/fb33d64d5d47d927.png)
所以通过newRetrofit方法,我们就将Retrofit对象配置好并且拿到Retrofit对象,还保存起来方便下次复用
在看看newCreate()方法
这是个扩展函数,是Retrofit的扩展函数
将传入的ConfigService通过Retrofit.create()生成代理类,并且保存起来复用
![](https://img.haomeiwen.com/i12417772/82f9c65fd78833b0.png)
自定义注解
AutoApi注解介绍
我们从最简单的AutoApi
做引子,开始介绍整个注解框架
只要你的接口类方法中使用了这个注解,就会生成suspend
方法,非常的简单
接着我们来看看他是怎么实现的
![](https://img.haomeiwen.com/i12417772/c4c1b23e6cdf94e6.png)
![](https://img.haomeiwen.com/i12417772/035a92f971f5bd9b.png)
看一下这个注解是怎么定义的
注解是支持有默认值的,因为kotlin的方法是可以在变量中直接赋初值的,这样调用就不用传值了,所以这里也做一个支持,让调用时候更加简洁
![](https://img.haomeiwen.com/i12417772/480138c9b826b799.png)
生成的流程
![](https://img.haomeiwen.com/i12417772/2a267778860268ca.png)
代码的分析
这里还是用ConfigService来分析
![](https://img.haomeiwen.com/i12417772/db75418273aab9f8.png)
【1】首先流程图,我们会遍历出使用这个注解的类,此时我们就已经拿到了ConfigService这个元素的所有信息了。
【2】接着我们会对ConfigService将包装起来,将他存在RepositoryClass类中。
RepositoryClass这个类会保存ConfigService的类名,包名,类型和所有方法等
![](https://img.haomeiwen.com/i12417772/02a2d3d732353486.png)
【3】会将ConfigService里的方法包装成AutoMethod(不同的注解会有不同的类型),存入RepositoryClass的method变量中
![](https://img.haomeiwen.com/i12417772/8680371c60c095a5.png)
![](https://img.haomeiwen.com/i12417772/b7b356f39a5128d5.png)
通过上述操作后,repositoryMap就存在所有使用过AutoAPi注解的类了,再将他做遍历,传入Repository类的生成器RepositoryClassBuilder
![](https://img.haomeiwen.com/i12417772/c0eff08b24047d49.png)
这个如果不添加startFuncBuild
方法的话,这段代码就只会生成
open class ConfigRepository : BaseRepository<ConfigService>() {
}
![](https://img.haomeiwen.com/i12417772/8aee7dae6fb85bee.png)
再来看看startFunBuild
,根据你当前类中的方法使用的注解去选择对应的方法处理器
![](https://img.haomeiwen.com/i12417772/2b89f595af4d1070.png)
所有的方法处理器都是继承AbsFuncBuilder
的
而子类需要对方法内的具体内容做输出,也可以在方法参数上做添加
![](https://img.haomeiwen.com/i12417772/dcace75e84e4099a.png)
AbsFuncBuilder
类只会生成如下代码,他会将前面RepositoryMethod
收集的信息做一个输出。但是具体内容还是交由子类去输出的,因为每个注解对应输出的方法体是不一样的
suspend fun config2(page: String = "GS"): List<String> {
// 具体内容是由子类完成的
}
NetStrategy注解
这个注解可以传4个参数
strategy
是缓存策略,effectiveTime
是缓存时间,timeUnit
是时间单位。
缓存策略默认是添加在方法上的,有时候同一个接口可能会因为不同场景而使用不同的缓存策略。
比如在刚进入主页时,使用页面初始化CacheFirst
页面初始化后,再次下拉加载数据,使用NetCache
在当前主页上拉加载,使用NetOnly
此时一个接口会分别使用三个不同的缓存策略
所以用isNeedAddParameter
来判断,需不需要在方法参数中添加缓存策略的参数
![](https://img.haomeiwen.com/i12417772/c5ccbae63fd57042.png)
代码的分析
NetStrategy的收集必须放在注解处理器的最后面,因为我展示想不到有什么好办法可以知道,NetStrategy这个注解,是与哪个方法注解捆绑使用了。
所以必须在前面的注解收集完毕后,当我再次收集使用过NetStrategy注解的方法时,拿到方法名,再与repositoryMap中储存的类的方法名做比较,如果一致,则表示该方法使用了NetStrategy注解,需要做缓存
![](https://img.haomeiwen.com/i12417772/421cfd8674259db6.png)
AutoFlowApi注解介绍
使用注解生成的代码
下面分析一下生成方法的各个方法
![](https://img.haomeiwen.com/i12417772/f39d11962bd53b4c.png)
viewModelScopeCoroutine
一个与viewmodel生命周期绑定的协程,默认在主线程运行
![](https://img.haomeiwen.com/i12417772/bbaffe2d5678b0b7.png)
![](https://img.haomeiwen.com/i12417772/1a850f28ffa1be02.png)
这里不好解释,我直接画图了
![](https://img.haomeiwen.com/i12417772/159a4670d40f0450.png)
CoroutineDataFetcher { apiService.getData() }.startFetchData()
apiService.getData() 就是发起网络请求
看一下CoroutineDataFetcher
![](https://img.haomeiwen.com/i12417772/1dc2521cc8ce8a79.png)
startFetchData(),就是根据传入的缓存参数,去找到对应的缓存策略发起Http请求的方法,很简单看一看就好
![](https://img.haomeiwen.com/i12417772/5eff6752e7db4079.png)
AutoFlowApi 代码
通过上面分析我们可以知道,你新写一个注解,其实就只需要编写两个类就好了
一个继承 RepositoryMethod
的参数收集器
一个继承 AbsFuncBuilder
的方法具体内容输出器
所以我们直接看到AutoFlowApi的这两个类
AutoFlowMethod
可以说和 AtoMethod 一模一样了,都是收集默认参数
不一样的地方就是下面的一些配置
![](https://img.haomeiwen.com/i12417772/2cb2fde850b1d232.png)
通过重写 AbsFuncBuilder
的暴露出来的配置方法,去修改方法的配置信息,比如图中的
isNullable
,方法返回值能否为null
isNeedSuspend
,方法是否是需要suspend关键字
isNeedReturnType
,方法是否需要返回值
![](https://img.haomeiwen.com/i12417772/5c2b2c8a7e2af618.png)
AutoFlowApiFuncBuilder
这个是AutoFlowApi注解最关键的方法了,里面代码比较多,但是也没什么好解释的,就是对kotlinpoet的使用,比较繁琐且无聊。
就是将你要生成的语句写出来,然后变量用规定字符代替
![](https://img.haomeiwen.com/i12417772/44a8852b35163cef.png)
接着就是生成句子,将语句里面的规定字符,用你的变量去替代就好了
![](https://img.haomeiwen.com/i12417772/c1bf57637786d269.png)
结尾
其实这个框架写的时候没考虑其全面性和兼容性,就打算先写出来试一试。其实还有很多地方可以修改和扩展。
网友评论