嗶哩嗶哩在Hilt組件化的使用技術(shù)探索
前言
DI(Dependency Injection),即“依賴注入”:組件之間依賴關(guān)系由容器在運(yùn)行期決定,形象的說,即由容器動(dòng)態(tài)的將某個(gè)依賴關(guān)系注入到組件之中。依賴注入的目的并非為軟件系統(tǒng)帶來更多功能,而是為了提升組件重用的頻率,并為系統(tǒng)搭建一個(gè)靈活、可擴(kuò)展的平臺。通過依賴注入機(jī)制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標(biāo)需要的資源,完成自身的業(yè)務(wù)邏輯,而不需要關(guān)心具體的資源來自何處,由誰實(shí)現(xiàn)。
最近業(yè)務(wù)同學(xué)需要接入谷歌推的Hilt框架。因?yàn)閱袅▎袅ǖ臉I(yè)務(wù)上很容易出現(xiàn)業(yè)務(wù)層面的交叉,而因?yàn)轫?xiàng)目完成了大量的組件化拆分。由于不希望業(yè)務(wù)之間產(chǎn)生相互引用,所有在技術(shù)評估完成之后我們決定由我們部門來對Hilt進(jìn)行接入。
接入Hilt
摘自官方文檔 使用 Hilt 實(shí)現(xiàn)依賴項(xiàng)注入
首先先聲明下dagger.hilt.android.plugin相關(guān)的plugin。
buildscript {
...
dependencies {
...
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.35.1'
}
}
其次由于hilt一大部分相關(guān)的都是基于kapt的代碼生成邏輯,所以我們要在使用到hilt的模塊的build.gradle中都定義如下相關(guān)的。
...
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
android {
...
}
dependencies {
implementation "com.google.dagger:hilt-android:2.35.1"
kapt "com.google.dagger:hilt-android-compiler:2.35.1"
}
我們需要給我們的Application增加一個(gè)注解。
@HiltAndroidApp
class ExampleApplication : Application() { }
根據(jù)官方接入文檔哦,我們組只要把Application只要打上@HiltAndroidApp的注解,就可以完成這部分接入能力了。
Hilt在組件化
但是但是官方有個(gè)聲明是這樣的。
Hilt 代碼生成操作需要訪問使用 Hilt 的所有 Gradle 模塊。編譯 Application 類的 Gradle 模塊需要在其傳遞依賴項(xiàng)中包含所有 Hilt 模塊和通過構(gòu)造函數(shù)注入的類。
從這部分說明上來看,這個(gè)注解最好是能放在com.android.application模塊中, 這樣就能保證依賴到所有的子模塊中去了。
但是實(shí)際我們在使用過程中,由于com.android.application模塊還是有一些代碼量的,而由于kapt代碼生成機(jī)制,需要先將kotlin代碼轉(zhuǎn)化成java代碼,之后才能生成ast語法樹。
根據(jù)ci上的實(shí)驗(yàn)結(jié)果,在com.android.application模塊下kapt耗時(shí)在30s左右,而整體編譯時(shí)間大概為3分鐘左右。這種耗時(shí)我個(gè)人覺得還是屬于不能接受的。
所以我們調(diào)整了下這部分代碼。這次建立了一個(gè)殼module,這邊只有HiltApplication的注解相關(guān)。然后將這個(gè)module依賴了所有業(yè)務(wù)倉庫,按照編譯邏輯來說,基于gradle task的depend邏輯,他會(huì)在application模塊編譯之前,所有業(yè)務(wù)模塊編譯之后,這樣能保證hilt生成的代碼邏輯正常。
同時(shí)由于是一個(gè)空工程,我們把空工程定義為bundle-kapt,所以整體來說對于編譯速度影響會(huì)變到最小。讓各位大佬看下我們后續(xù)的優(yōu)化結(jié)果。

上述是我最后截圖出來的結(jié)果,我們將一個(gè)耗時(shí)大概30s的任務(wù)優(yōu)化到3s,其實(shí)效果上來說已經(jīng)非常明顯,達(dá)到我們想要的預(yù)期了已經(jīng)。
當(dāng)然如果后續(xù)hilt支持了ksp之后,這部分速度應(yīng)該可以更快,畢竟我么可以直接拋棄java語法樹了嗎。
出現(xiàn)了點(diǎn)小問題
這兩天業(yè)務(wù)方實(shí)際在使用過程中,突然反饋說貌似我們接入的Hilt貌似不行啊,進(jìn)入到頁面直接崩潰了。
有一說一,一臉懵逼。先看看異常吧。初一開始我以為是kapt沒有生成好或者別的什么原因?qū)е碌摹?/p>
com.xxxxxx.xxxxxx}: java.lang.ClassCastException: xxxxx.DaggerHiltApplication_HiltComponents_SingletonC$ActivityRetainedCImpl$ActivityCImpl cannot be cast to xxxxx_GeneratedInjector
只能一步步調(diào)試咯,我打開項(xiàng)目開啟編譯項(xiàng)目,之后進(jìn)入蠻長的等待過程中。10分鐘過去了終于好了。

由于Hilt使用了kapt,所以很自然的打開了build/generated/source/kapt文件路徑,之后我看了下DaggerHiltApplication_HiltComponents_SingletonC這個(gè)類的生成。

ActivityRetainedCImpl從這里我大概猜測出了一小部分Hilt原理,通過收集不同子Module的抽象接口,然后把這部分能力聚合在HiltApplication中,舉個(gè)例子Hilt_BangumiDetailActivityV3這個(gè)就是一個(gè)子業(yè)務(wù)內(nèi)的DI注入的一個(gè)類的實(shí)現(xiàn)。
突然這個(gè)時(shí)候我想到了一件事哦,也就是說我們的bundle-kapt模塊,其實(shí)它的實(shí)際編譯產(chǎn)物會(huì)根據(jù)接入業(yè)務(wù)的不同而產(chǎn)生實(shí)際的變更。也就是說雖然這個(gè)模塊的代碼沒有發(fā)生變更,但是由于子業(yè)務(wù)增加了注解和代碼變更,導(dǎo)致了這個(gè)模塊的kapt還是需要重新執(zhí)行,這樣才能保證輸出的產(chǎn)物是變化的。
然而我們的項(xiàng)目之前由于工程結(jié)構(gòu)太龐大了,可能有30-40個(gè)Module,所有我們將一部分沒有變更的代碼產(chǎn)物化,也就是基于commit變成了一個(gè)個(gè)aar或者jar發(fā)布到了遠(yuǎn)端。之后根據(jù)commit來重新定向到產(chǎn)物。
而bundle-kapt這個(gè)模塊也很不幸,被當(dāng)做了一個(gè)靜態(tài)模塊,變成了一個(gè)遠(yuǎn)端的產(chǎn)物,之后即時(shí)業(yè)務(wù)添加了再多的注入相關(guān)的,因?yàn)閎undle-kapt沒有參與編譯,所以注入的能力就出錯(cuò)了。
總結(jié)
我們團(tuán)隊(duì)算是一個(gè)比較好玩的團(tuán)隊(duì)了,團(tuán)隊(duì)有兩位巨佬,一位大佬專門負(fù)責(zé)編譯相關(guān)的,基本gradle方面都懂了,而且玩的也很花里胡哨的。另外一位大佬l(wèi)ancet作者,gradle方面懂得多就不提了,上一篇文章最后的問題也是這位大佬幫忙處理的。
而其他的組員其實(shí)人也都非常的不錯(cuò),而且我們團(tuán)隊(duì)也做了很多東西。比如之前介紹的網(wǎng)絡(luò)優(yōu)化,資源混淆插件優(yōu)化,圖片中間件,動(dòng)態(tài)化,自研的路由框架,還有blkv自研的ky存儲框架等等。
同樣的我們的kt版本還有agp版本都算是業(yè)內(nèi)比較靠前的了。一方面是大佬能cover住,另一方面我們也會(huì)在這部分投入人力,我們也已經(jīng)開始用viewbinding的代理啦
以上就是嗶哩嗶哩在Hilt組件化的使用技術(shù)探索的詳細(xì)內(nèi)容,更多關(guān)于嗶哩嗶哩Hilt組件化使用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android編程實(shí)現(xiàn)簡單文件瀏覽器功能
這篇文章主要介紹了Android編程實(shí)現(xiàn)簡單文件瀏覽器功能,結(jié)合實(shí)例形式分析了Android文件管理器的布局、文件與目錄的遍歷、權(quán)限控制等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01
老項(xiàng)目遷移AndroidStudio3.0遇到的坑
給大家分享了老的項(xiàng)目以及程序遷移到了AndroidStudio3.0遇到的坑和問題解決辦法,希望給你做個(gè)參考。2017-11-11
Android應(yīng)用開發(fā)中自定義ViewGroup的究極攻略
這里我們要演示的自定義ViewGroup中將實(shí)現(xiàn)多種方式排列和滑動(dòng)等效果,并且涵蓋子View之間Touch Event的攔截與處理等問題,完全干貨,下面就為大家送上Android應(yīng)用開發(fā)中自定義ViewGroup的究極實(shí)例攻略2016-05-05
Kotlin開發(fā)中open關(guān)鍵字與類名函數(shù)名和變量名的使用方法淺析
這篇文檔中,我們將解釋如何以及為什么將 open 關(guān)鍵字與類名、函數(shù)名和變量名一起使用,了解內(nèi)部原理是為了幫助我們做擴(kuò)展,同時(shí)也是驗(yàn)證了一個(gè)人的學(xué)習(xí)能力,如果你想讓自己的職業(yè)道路更上一層樓,這些底層的東西你是必須要會(huì)的2023-02-02
Android TextView中文字通過SpannableString設(shè)置屬性用法示例
這篇文章主要介紹了Android TextView中文字通過SpannableString設(shè)置屬性用法,結(jié)合實(shí)例形式分析了TextView控件中SpannableString類相關(guān)屬性的使用技巧,需要的朋友可以參考下2016-08-08
Android中Intent機(jī)制詳解及示例總結(jié)(總結(jié)篇)
本文是小編日常收集整理些有關(guān)Android中Intent機(jī)制詳解及示例總結(jié),對android中intent相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧2016-04-04
詳解Android——藍(lán)牙技術(shù) 帶你實(shí)現(xiàn)終端間數(shù)據(jù)傳輸
藍(lán)牙技術(shù)在智能硬件方面有很多用武之地,本篇文章主要介紹了Android——藍(lán)牙技術(shù),實(shí)現(xiàn)兩個(gè)終端間數(shù)據(jù)的傳輸,有興趣的朋友可以了解一下。2016-12-12
基于fluttertoast實(shí)現(xiàn)封裝彈框提示工具類
這篇文章主要為大家介紹了基于fluttertoast實(shí)現(xiàn)封裝彈框提示工具類的實(shí)現(xiàn)代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05

