對(duì)項(xiàng)目的基本介紹
1.整個(gè)框架主要是給MVVM框架使用的,自己寫完interface接口后,通過(guò)自定義的注解就能自動(dòng)生成接口方法
2.用Kotlin的Flow去代替Rxjava,因?yàn)槲野l(fā)現(xiàn)RxJava功能很強(qiáng)大,但是大家都只是在Http層面使用了一下,既然要用Kotlin里面就已經(jīng)有Flow,那我還不如少添加一個(gè)庫(kù)
3.通過(guò)jetpack的Room數(shù)據(jù)庫(kù)實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的存儲(chǔ),緩存策略也用過(guò)注解去完成。
4.發(fā)起的網(wǎng)絡(luò)請(qǐng)求是與宿主生命周期綁定的,在網(wǎng)絡(luò)請(qǐng)求回來(lái)之前,宿主已經(jīng)銷毀的話,網(wǎng)絡(luò)請(qǐng)求也會(huì)中斷的
基本使用方法
1.先定義接口類
和Retrofit一樣,需要定義一個(gè)接口類
其中@AutoApi,@AutoFlowApi,@NetStrategy是自定義的注解,后面會(huì)介紹到。

2.要先編譯,會(huì)在你的接口類的文件夾下生成一個(gè)xxxRepository.class
這是通過(guò)注解自動(dòng)生成的文件,使用了kotlinpoet
并且這里apiService就是通過(guò)Retrofit拿到的接口代理

3.在viewmodel拿到對(duì)應(yīng)Repository類的方法

4.在對(duì)應(yīng)地方通過(guò)viewmodel調(diào)用
調(diào)用接口,傳入對(duì)應(yīng)參數(shù)

在合適的地方觀察

Retrofit的封裝
上面說(shuō)到在Repository類的apiService就是通過(guò)Retrofit拿到的接口代理類。
所以先進(jìn)去看看apiService好了
可以看到apiService是BaseRepository的變量
而我們生成的Repository都是繼承BaseRepository的

當(dāng)我們調(diào)ConfigRepository類中的方法時(shí)候,就會(huì)將ConfigRepository傳入findNeedType

而findNeedType方法就會(huì)將ConfigRepository對(duì)應(yīng)的ConfigService得到并且返回出去

所以apiService就相當(dāng)于這樣,好像有點(diǎn)Retrofit的create方法的樣子了
var apiService: T = HttpProvider.defaultCreate(ConfigService) as Class<out T>)
我們繼續(xù)進(jìn)入HttpProvider.defaultCreate
可以看到newRetrofit(),并且傳入了一個(gè)HttpConfig,看到這個(gè)名字就知道這是Http的配置
接著是newCreate(),接收了我們的接口service類

首先看看newRetrofit方法
這幾行代碼就是創(chuàng)建了一個(gè)Retrofit對(duì)象并且保存起來(lái),最后返回出去。
但是他是怎么和HttpConfig聯(lián)系起來(lái)的呢?

我們可以看到這里將生成的Retrofit.Builder()傳給了HttpConfig的方法build里,我們進(jìn)去看一看

可以看到這里就是我們?cè)偈煜げ贿^(guò)的Retrofit的配置環(huán)節(jié)

所以通過(guò)newRetrofit方法,我們就將Retrofit對(duì)象配置好并且拿到Retrofit對(duì)象,還保存起來(lái)方便下次復(fù)用
在看看newCreate()方法
這是個(gè)擴(kuò)展函數(shù),是Retrofit的擴(kuò)展函數(shù)
將傳入的ConfigService通過(guò)Retrofit.create()生成代理類,并且保存起來(lái)復(fù)用

自定義注解
AutoApi注解介紹
我們從最簡(jiǎn)單的AutoApi做引子,開(kāi)始介紹整個(gè)注解框架
只要你的接口類方法中使用了這個(gè)注解,就會(huì)生成suspend方法,非常的簡(jiǎn)單
接著我們來(lái)看看他是怎么實(shí)現(xiàn)的


看一下這個(gè)注解是怎么定義的
注解是支持有默認(rèn)值的,因?yàn)閗otlin的方法是可以在變量中直接賦初值的,這樣調(diào)用就不用傳值了,所以這里也做一個(gè)支持,讓調(diào)用時(shí)候更加簡(jiǎn)潔

生成的流程

代碼的分析
這里還是用ConfigService來(lái)分析

【1】首先流程圖,我們會(huì)遍歷出使用這個(gè)注解的類,此時(shí)我們就已經(jīng)拿到了ConfigService這個(gè)元素的所有信息了。
【2】接著我們會(huì)對(duì)ConfigService將包裝起來(lái),將他存在RepositoryClass類中。
RepositoryClass這個(gè)類會(huì)保存ConfigService的類名,包名,類型和所有方法等

【3】會(huì)將ConfigService里的方法包裝成AutoMethod(不同的注解會(huì)有不同的類型),存入RepositoryClass的method變量中


通過(guò)上述操作后,repositoryMap就存在所有使用過(guò)AutoAPi注解的類了,再將他做遍歷,傳入Repository類的生成器RepositoryClassBuilder

這個(gè)如果不添加startFuncBuild方法的話,這段代碼就只會(huì)生成
open class ConfigRepository : BaseRepository<ConfigService>() {
}

再來(lái)看看startFunBuild,根據(jù)你當(dāng)前類中的方法使用的注解去選擇對(duì)應(yīng)的方法處理器

所有的方法處理器都是繼承AbsFuncBuilder的
而子類需要對(duì)方法內(nèi)的具體內(nèi)容做輸出,也可以在方法參數(shù)上做添加

AbsFuncBuilder類只會(huì)生成如下代碼,他會(huì)將前面RepositoryMethod收集的信息做一個(gè)輸出。但是具體內(nèi)容還是交由子類去輸出的,因?yàn)槊總€(gè)注解對(duì)應(yīng)輸出的方法體是不一樣的
suspend fun config2(page: String = "GS"): List<String> {
// 具體內(nèi)容是由子類完成的
}
NetStrategy注解
這個(gè)注解可以傳4個(gè)參數(shù)
strategy 是緩存策略,effectiveTime是緩存時(shí)間,timeUnit是時(shí)間單位。
緩存策略默認(rèn)是添加在方法上的,有時(shí)候同一個(gè)接口可能會(huì)因?yàn)椴煌瑘?chǎng)景而使用不同的緩存策略。
比如在剛進(jìn)入主頁(yè)時(shí),使用頁(yè)面初始化CacheFirst
頁(yè)面初始化后,再次下拉加載數(shù)據(jù),使用NetCache
在當(dāng)前主頁(yè)上拉加載,使用NetOnly
此時(shí)一個(gè)接口會(huì)分別使用三個(gè)不同的緩存策略
所以用isNeedAddParameter來(lái)判斷,需不需要在方法參數(shù)中添加緩存策略的參數(shù)

代碼的分析
NetStrategy的收集必須放在注解處理器的最后面,因?yàn)槲艺故鞠氩坏接惺裁春棉k法可以知道,NetStrategy這個(gè)注解,是與哪個(gè)方法注解捆綁使用了。
所以必須在前面的注解收集完畢后,當(dāng)我再次收集使用過(guò)NetStrategy注解的方法時(shí),拿到方法名,再與repositoryMap中儲(chǔ)存的類的方法名做比較,如果一致,則表示該方法使用了NetStrategy注解,需要做緩存

AutoFlowApi注解介紹
使用注解生成的代碼
下面分析一下生成方法的各個(gè)方法

viewModelScopeCoroutine
一個(gè)與viewmodel生命周期綁定的協(xié)程,默認(rèn)在主線程運(yùn)行


這里不好解釋,我直接畫圖了

CoroutineDataFetcher { apiService.getData() }.startFetchData()
apiService.getData() 就是發(fā)起網(wǎng)絡(luò)請(qǐng)求
看一下CoroutineDataFetcher

startFetchData(),就是根據(jù)傳入的緩存參數(shù),去找到對(duì)應(yīng)的緩存策略發(fā)起Http請(qǐng)求的方法,很簡(jiǎn)單看一看就好

AutoFlowApi 代碼
通過(guò)上面分析我們可以知道,你新寫一個(gè)注解,其實(shí)就只需要編寫兩個(gè)類就好了
一個(gè)繼承 RepositoryMethod 的參數(shù)收集器
一個(gè)繼承 AbsFuncBuilder 的方法具體內(nèi)容輸出器
所以我們直接看到AutoFlowApi的這兩個(gè)類
AutoFlowMethod
可以說(shuō)和 AtoMethod 一模一樣了,都是收集默認(rèn)參數(shù)
不一樣的地方就是下面的一些配置

通過(guò)重寫 AbsFuncBuilder 的暴露出來(lái)的配置方法,去修改方法的配置信息,比如圖中的
isNullable,方法返回值能否為null
isNeedSuspend,方法是否是需要suspend關(guān)鍵字
isNeedReturnType,方法是否需要返回值

AutoFlowApiFuncBuilder
這個(gè)是AutoFlowApi注解最關(guān)鍵的方法了,里面代碼比較多,但是也沒(méi)什么好解釋的,就是對(duì)kotlinpoet的使用,比較繁瑣且無(wú)聊。
就是將你要生成的語(yǔ)句寫出來(lái),然后變量用規(guī)定字符代替

接著就是生成句子,將語(yǔ)句里面的規(guī)定字符,用你的變量去替代就好了

結(jié)尾
其實(shí)這個(gè)框架寫的時(shí)候沒(méi)考慮其全面性和兼容性,就打算先寫出來(lái)試一試。其實(shí)還有很多地方可以修改和擴(kuò)展。