Android Hilt的使用以及遇到的問(wèn)題
簡(jiǎn)介
Hilt 提供了一種將Dagger 依賴注入到Android 應(yīng)用程序的標(biāo)準(zhǔn)方法。為Android 應(yīng)用程序簡(jiǎn)化提供一組標(biāo)準(zhǔn)的、簡(jiǎn)化設(shè)置、可以讀的組件;且為不同類型的構(gòu)建(例如:測(cè)試、調(diào)試、發(fā)行)提供一種簡(jiǎn)單的方法。
可以理解為Google 為了統(tǒng)一依賴注入組件,但是Dagger 用起來(lái)比較復(fù)雜。就針對(duì)Android開(kāi)發(fā)了一套適配庫(kù)。
導(dǎo)入Hilt
apply plugin: 'com.android.application' apply plugin: 'dagger.hilt.android.plugin' android { // ... } dependencies { implementation 'com.google.dagger:hilt-android:2.34.1-beta' kapt 'com.google.dagger:hilt-compiler:2.34.1-beta' // For instrumentation tests androidTestImplementation 'com.google.dagger:hilt-android-testing:2.34.1-beta' kaptAndroidTest 'com.google.dagger:hilt-compiler:2.34.1-beta' // For local unit tests testImplementation 'com.google.dagger:hilt-android-testing:2.34.1-beta' kaptTest 'com.google.dagger:hilt-compiler:2.34.1-beta' } kapt { correctErrorTypes true }
設(shè)置correctErrorTypes 為true ,將kapt配置為更正錯(cuò)誤類型 。
這里遇到一個(gè)問(wèn)題,當(dāng)我的gradle 版本為 3.4.1 的時(shí)候
classpath 'com.android.tools.build:gradle:3.4.1'
apply plugin: 'dagger.hilt.android.plugin'插件一直安裝失敗,
提示找不到 "com/android/Version" 把gradle 改成 4.1.2 就沒(méi)問(wèn)題了
且注意 如果你是多module的項(xiàng)目,
apply plugin: 'dagger.hilt.android.plugin' 一定要plugin在主module下
(也就是跟 apply plugin: 'com.android.application' 一起),
若是只在子module下,主module的注入不會(huì)被實(shí)現(xiàn)。(問(wèn)題1,后面會(huì)解釋問(wèn)題原因)
buildscript { repositories { // other repositories... mavenCentral() } dependencies { // other plugins... classpath 'com.google.dagger:hilt-android-gradle-plugin:2.34.1-beta' } }
組件層次
Hilt把Dagger 手動(dòng)創(chuàng)建Component 改成了預(yù)定義的Component,且自動(dòng)集成到Android應(yīng)用程序的各個(gè)生命周期中。通過(guò)注解的方式@InstallIn(xxxComponent.class)進(jìn)行綁定。
下圖顯示了標(biāo)準(zhǔn)的Hilt組件層次結(jié)構(gòu)。每個(gè)組件上方的注釋是作用域注釋,用于將綁定范圍限制為該組件的生存期。組件下方的箭頭指向任何子組件。通常,子組件中的綁定可以依賴于祖先組件中的任何綁定。
組件默認(rèn)綁定
每個(gè)Hilt 組件都帶有一組默認(rèn)綁定,這些默認(rèn)綁定可以作為依賴注入到你自定義綁定中
Component | Default Bindings |
---|---|
SingletonComponent | Application |
ActivityRetainedComponent | Application |
ViewModelComponent | SavedStateHandle |
ActivityComponent | Application, Acitvity |
FragmentComponent | Application, Acitvity, Fragment |
ViewComponent | Application, Acitvity, View |
ViewWithFragmentComponent | Application, Acitvity, Fragment, View |
ServiceComponent | Application, Service |
簡(jiǎn)單使用
下面我為大家介紹以下一些注解的使用:
- @HiltAndroidApp
- @AndroidEntryPoint
- @InstallIn
- @Module
- @Provides
- @Binds
- @HiltViewModel
- @EntryPoint
想要了解更多的建議直接查看官方文檔
@HiltAndroidApp
介紹
所有使用Hilt的App 必須包含一個(gè)被@HiltAndroidApp 注釋的Appliction 類。
@HiltAndroidApp 會(huì)生成一個(gè)Hilt_MyApplication 的基類,并且繼承與@HiltAndroidApp 注釋的類的基類,然后將@HiltAndroidApp 注釋的類的基類替換成Hilt_MyApplication。例如:
這是我們應(yīng)用的 MyApplication
@HiltAndroidApp class MyApplication extends BaseApplication{ }
使用@HiltAndroidApp Hilt 將會(huì)生成 Hilt_MyApplication
public abstract class Hilt_MyApplication extends BaseApplication implements GeneratedComponentManagerHolder { private final ApplicationComponentManager componentManager = new ApplicationComponentManager(new ComponentSupplier() { @Override public Object get() { return DaggerMyApplication_HiltComponents_SingletonC.builder() .applicationContextModule(new ApplicationContextModule(Hilt_MyApplication.this)) .build(); } }); @Override public final ApplicationComponentManager componentManager() { return componentManager; } @Override public final Object generatedComponent() { return this.componentManager().generatedComponent(); } @CallSuper @Override public void onCreate() { // This is a known unsafe cast, but is safe in the only correct use case: // MyApplication extends Hilt_MyApplication ((MyApplication_GeneratedInjector) generatedComponent()).injectMyApplication(UnsafeCasts.<MyApplication>unsafeCast(this)); super.onCreate(); } }
并且使我們的 MyApplication 繼承 Hilt_MyApplication,通過(guò)這種方式將modules 注入到我們的應(yīng)用中。
可以看到具體的注入方法就是Hilt_MyApplication onCreate() 函數(shù)中的
((MyApplication_GeneratedInjector) generatedComponent()).injectMyApplication(UnsafeCasts.unsafeCast(this));
這句代碼,generatedComponent() 返回的是 MyApplication_HiltComponents.SingletonC 對(duì)象,這個(gè)對(duì)象中就是我們所有module 的代碼實(shí)現(xiàn)。有興趣的同學(xué)可以自己去看一下,我這里就不貼代碼了
使用
使用分為兩種情況,添加和沒(méi)有添加 Hilt Gradle插件
//沒(méi)有添加插件 @HiltAndroidApp(BaseApplication.class) class MyApplication extends Hilt_MyApplication{} //添加插件 @HiltAndroidApp class MyApplication extends BaseApplication{}
建議添加插件,使用起來(lái)會(huì)更簡(jiǎn)單。本文以下的示例都假定以使用插件。
這里需要注意的是如果要在MyApplication 中使用注入的對(duì)象,需要在 super.onCreate() 之后才能使用。 原因且看介紹中的 Hilt_MyApplication 源碼。
這里解釋一下問(wèn)題1出現(xiàn)的原因,是因?yàn)槲覜](méi)有添加插件但@HiltAndroidApp 使用的時(shí)候用的卻是添加了插件的用法。所以會(huì)出現(xiàn)module 注入不被實(shí)現(xiàn)的情況。
@AndroidEntryPoint
介紹
安卓成員注入,使用@AndroidEntryPoint 注解后就可以在該類中使用module注入的成員變量。但@AndroidEntryPoint 有類型限制,只能在以下的類上使用:
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
使用
@AndroidEntryPoint public final class MyActivity extends MyBaseActivity { // Bindings in SingletonComponent or ActivityComponent @Inject Bar bar; @Override public void onCreate(Bundle savedInstanceState) { // Injection happens in super.onCreate(). super.onCreate(); // Do something with bar ... } }
同樣要注意是是需要在 super.onCreate() 后使用注入的成員變量
@Module 和 @InstallIn
介紹
@Module 跟Dagger 里的是同一個(gè),沒(méi)什么好說(shuō)的。
@InstallIn 通過(guò)使用@InstallIn(xxxComponent.class) 將module 安裝到指定的組件中,在Hilt 中所以module 都必須添加這個(gè)注釋,如果組件中就找不到這個(gè)module ,可能引起編譯錯(cuò)誤。
當(dāng)然一個(gè)module 也可安裝到多個(gè)組件上如:@InstallIn({ViewComponent.class, ViewWithFragmentComponent.class})
使用
@Module @InstallIn(SingletonComponent.class) public final class FooModule { // @InstallIn(SingletonComponent.class) module providers have access to // the Application binding. @Provides static Bar provideBar(Application app) {...} }
每個(gè)組件都帶有作用域注釋,該注釋可用于記住對(duì)組件生存期的綁定。例如,要將范圍綁定到 SingletonComponent組件,請(qǐng)使用@Singleton批注:
@Module @InstallIn(SingletonComponent.class) public final class FooModule { // @Singleton providers are only called once per SingletonComponent instance. @Provides @Singleton static Bar provideBar() {...} }
此外,每個(gè)組件都有默認(rèn)情況下可用的綁定。例如,該SingletonComponent組件提供了Application 綁定:
@Module @InstallIn(SingletonComponent.class) public final class FooModule { // @InstallIn(SingletonComponent.class) module providers have access to // the Application binding. @Provides static Bar provideBar(Application app) {...} }
@Provides 和 @Binds
介紹
@Provides 注釋Module 中的方法以創(chuàng)建提供者方法綁定。該方法的返回類型綁定到其返回值。
@Binds 注釋Module 中的抽象方法,一般方法的返回是一個(gè)接口,參數(shù)是實(shí)現(xiàn)接口的子類,在調(diào)用是會(huì)調(diào)用參數(shù)的子類中的方法實(shí)現(xiàn)。
使用
@Module @InstallIn(SingletonComponent.class) public final class FooModule { @Provides @Singleton static Bar provideBar() {...} } @Module @InstallIn(SingletonComponent.class) public abstract class BindModule { @Binds @Singleton abstract Random bindRandom(SecureRandom secureRandom); }
@HiltViewModel
介紹
使用 @HiltViewModel 注釋ViewModel,ViewModel 在創(chuàng)建的時(shí)候就會(huì)走Hilt 創(chuàng)建的HiltViewModelFactory 進(jìn)行創(chuàng)建。就可以使用在創(chuàng)建的時(shí)候使用Module 中提供的實(shí)例
使用
@HiltViewModel public final class FooViewModel extends ViewModel { @Inject FooViewModel(SavedStateHandle handle, Foo foo) { // ... } }
然后就可以在帶有@AndroidEntryPoint 注解的activity、fragment 中使用了
@AndroidEntryPoint public final class MyActivity extends AppCompatActivity { private FooViewModel fooViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); fooViewModel = new ViewModelProvider(this).get(FooViewModel.class); } }
@EntryPoint
介紹
為不能使用注解的地方提供注入的對(duì)象。因?yàn)锧AndroidEntryPoint 使用范圍有限,在這范圍之外要使用Hilt 注入的實(shí)例就可以使用@EntryPoint 來(lái)實(shí)現(xiàn)。
這個(gè)像是Hilt 把Component標(biāo)準(zhǔn)化后,使用者不能再里面添加方法,導(dǎo)致不能為使用不了注解的地方提供依賴而做出的解決方案。
@EntryPoint @InstallIn(SingletonComponent.class) public interface FooBarInterface { Bar getBar(); }
如果使用上面的定義
Bar bar = EntryPoints.get(applicationContext, FooBarInterface.class).getBar();
小結(jié)
一開(kāi)始使用的時(shí)候我看到是 安卓開(kāi)發(fā)平臺(tái)“Hilt 和 Jetpack 集成”這個(gè)文檔,真坑,文檔不及時(shí)更新也不把官方鏈接放一下。吐槽一下。然后幾經(jīng)周轉(zhuǎn)找到了官方文檔才能有幸為大家介紹一下Hilt。
使用起來(lái)確實(shí)要比Dagger 舒服的多,少了很多模板代碼,范圍和生命周期的綁定也更好理解。不多bb 學(xué)它
以上就是Android Hilt的使用以及遇到的問(wèn)題的詳細(xì)內(nèi)容,更多關(guān)于Android Hilt的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android adb.exe程序啟動(dòng)不起來(lái) 具體解決方法
這篇文章主要介紹了Android adb.exe程序啟動(dòng)不起來(lái) 具體解決方法,有需要的朋友可以參考一下2013-12-12Android開(kāi)源堆疊滑動(dòng)控件仿探探效果
這篇文章主要為大家詳細(xì)介紹了Android開(kāi)源堆疊滑動(dòng)控件仿探探效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03Flutter實(shí)現(xiàn)滑動(dòng)塊驗(yàn)證碼功能
這篇文章主要為大家詳細(xì)介紹了Flutter實(shí)現(xiàn)滑動(dòng)塊驗(yàn)證碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Android GridView簡(jiǎn)單實(shí)例
這篇文章主要為大家詳細(xì)介紹了Android GridView簡(jiǎn)單實(shí)例,簡(jiǎn)單實(shí)現(xiàn)九宮格效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01Android Studio 中的Gradle構(gòu)建系統(tǒng)示例
這篇文章主要介紹了Android Studio 中的Gradle構(gòu)建系統(tǒng)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11