Android Hilt的使用以及遇到的問題
簡介
Hilt 提供瞭一種將Dagger 依賴註入到Android 應用程序的標準方法。為Android 應用程序簡化提供一組標準的、簡化設置、可以讀的組件;且為不同類型的構建(例如:測試、調試、發行)提供一種簡單的方法。
可以理解為Google 為瞭統一依賴註入組件,但是Dagger 用起來比較復雜。就針對Android開發瞭一套適配庫。
導入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 }
設置correctErrorTypes 為true ,將kapt配置為更正錯誤類型 。
這裡遇到一個問題,當我的gradle 版本為 3.4.1 的時候
classpath 'com.android.tools.build:gradle:3.4.1'
apply plugin: ‘dagger.hilt.android.plugin’插件一直安裝失敗,
提示找不到 “com/android/Version” 把gradle 改成 4.1.2 就沒問題瞭
且註意 如果你是多module的項目,
apply plugin: ‘dagger.hilt.android.plugin’ 一定要plugin在主module下
(也就是跟 apply plugin: ‘com.android.application’ 一起),
若是隻在子module下,主module的註入不會被實現。(問題1,後面會解釋問題原因)
buildscript { repositories { // other repositories... mavenCentral() } dependencies { // other plugins... classpath 'com.google.dagger:hilt-android-gradle-plugin:2.34.1-beta' } }
組件層次
Hilt把Dagger 手動創建Component 改成瞭預定義的Component,且自動集成到Android應用程序的各個生命周期中。通過註解的方式@InstallIn(xxxComponent.class)進行綁定。
下圖顯示瞭標準的Hilt組件層次結構。每個組件上方的註釋是作用域註釋,用於將綁定范圍限制為該組件的生存期。組件下方的箭頭指向任何子組件。通常,子組件中的綁定可以依賴於祖先組件中的任何綁定。
組件默認綁定
每個Hilt 組件都帶有一組默認綁定,這些默認綁定可以作為依賴註入到你自定義綁定中
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 |
簡單使用
下面我為大傢介紹以下一些註解的使用:
- @HiltAndroidApp
- @AndroidEntryPoint
- @InstallIn
- @Module
- @Provides
- @Binds
- @HiltViewModel
- @EntryPoint
想要瞭解更多的建議直接查看官方文檔
@HiltAndroidApp
介紹
所有使用Hilt的App 必須包含一個被@HiltAndroidApp 註釋的Appliction 類。
@HiltAndroidApp 會生成一個Hilt_MyApplication 的基類,並且繼承與@HiltAndroidApp 註釋的類的基類,然後將@HiltAndroidApp 註釋的類的基類替換成Hilt_MyApplication。例如:
這是我們應用的 MyApplication
@HiltAndroidApp class MyApplication extends BaseApplication{ }
使用@HiltAndroidApp Hilt 將會生成 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,通過這種方式將modules 註入到我們的應用中。
可以看到具體的註入方法就是Hilt_MyApplication onCreate() 函數中的
((MyApplication_GeneratedInjector) generatedComponent()).injectMyApplication(UnsafeCasts.unsafeCast(this));
這句代碼,generatedComponent() 返回的是 MyApplication_HiltComponents.SingletonC 對象,這個對象中就是我們所有module 的代碼實現。有興趣的同學可以自己去看一下,我這裡就不貼代碼瞭
使用
使用分為兩種情況,添加和沒有添加 Hilt Gradle插件
//沒有添加插件 @HiltAndroidApp(BaseApplication.class) class MyApplication extends Hilt_MyApplication{} //添加插件 @HiltAndroidApp class MyApplication extends BaseApplication{}
建議添加插件,使用起來會更簡單。本文以下的示例都假定以使用插件。
這裡需要註意的是如果要在MyApplication 中使用註入的對象,需要在 super.onCreate() 之後才能使用。 原因且看介紹中的 Hilt_MyApplication 源碼。
這裡解釋一下問題1出現的原因,是因為我沒有添加插件但@HiltAndroidApp 使用的時候用的卻是添加瞭插件的用法。所以會出現module 註入不被實現的情況。
@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 裡的是同一個,沒什麼好說的。
@InstallIn 通過使用@InstallIn(xxxComponent.class) 將module 安裝到指定的組件中,在Hilt 中所以module 都必須添加這個註釋,如果組件中就找不到這個module ,可能引起編譯錯誤。
當然一個module 也可安裝到多個組件上如:@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) {...} }
每個組件都帶有作用域註釋,該註釋可用於記住對組件生存期的綁定。例如,要將范圍綁定到 SingletonComponent組件,請使用@Singleton批註:
@Module @InstallIn(SingletonComponent.class) public final class FooModule { // @Singleton providers are only called once per SingletonComponent instance. @Provides @Singleton static Bar provideBar() {...} }
此外,每個組件都有默認情況下可用的綁定。例如,該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 中的方法以創建提供者方法綁定。該方法的返回類型綁定到其返回值。
@Binds 註釋Module 中的抽象方法,一般方法的返回是一個接口,參數是實現接口的子類,在調用是會調用參數的子類中的方法實現。
使用
@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 在創建的時候就會走Hilt 創建的HiltViewModelFactory 進行創建。就可以使用在創建的時候使用Module 中提供的實例
使用
@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
介紹
為不能使用註解的地方提供註入的對象。因為@AndroidEntryPoint 使用范圍有限,在這范圍之外要使用Hilt 註入的實例就可以使用@EntryPoint 來實現。
這個像是Hilt 把Component標準化後,使用者不能再裡面添加方法,導致不能為使用不瞭註解的地方提供依賴而做出的解決方案。
@EntryPoint @InstallIn(SingletonComponent.class) public interface FooBarInterface { Bar getBar(); }
如果使用上面的定義
Bar bar = EntryPoints.get(applicationContext, FooBarInterface.class).getBar();
小結
一開始使用的時候我看到是 安卓開發平臺“Hilt 和 Jetpack 集成”這個文檔,真坑,文檔不及時更新也不把官方鏈接放一下。吐槽一下。然後幾經周轉找到瞭官方文檔才能有幸為大傢介紹一下Hilt。
使用起來確實要比Dagger 舒服的多,少瞭很多模板代碼,范圍和生命周期的綁定也更好理解。不多bb 學它
以上就是Android Hilt的使用以及遇到的問題的詳細內容,更多關於Android Hilt的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- None Found