Dagger Hilt 注入 ActivityContext 时出错

Bar*_*fet 9 android dependency-injection dagger-2 dagger-hilt

我正在注入Dagger-Hilt一个依赖于@ActivityContextViewModel 的类,该模块安装在ActivityComponent活动中并限定范围,每当我尝试编译时,它都会抛出错误。供您参考,我还有其他带有 ActivityRetainedComponent 和 SingletonComponent 注入 @ApplicationContext 的模块。

\n

现在我试图弄清楚这个错误是什么意思。

\n
error: [Dagger/MissingBinding] com.rober.fileshortcut_whereismyfile.utils.PermissionsUtils cannot be provided without an @Inject constructor or an @Provides-annotated method.\n  public abstract static class SingletonC implements App_GeneratedInjector,\n                         ^\n      com.rober.fileshortcut_whereismyfile.utils.PermissionsUtils is injected at\n          com.rober.fileshortcut_whereismyfile.ui.fragments.filefragment.FileViewModel(\xef\xbf\xbd, permissionsUtils, \xef\xbf\xbd)\n      com.rober.fileshortcut_whereismyfile.ui.fragments.filefragment.FileViewModel is injected at\n          com.rober.fileshortcut_whereismyfile.ui.fragments.filefragment.FileViewModel_HiltModules.BindsModule.binds(vm)\n      @dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.String,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at\n          dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com.rober.fileshortcut_whereismyfile.App_HiltComponents.SingletonC ? com.rober.fileshortcut_whereismyfile.App_HiltComponents.ActivityRetainedC ? com.rober.fileshortcut_whereismyfile.App_HiltComponents.ViewModelC]\n
Run Code Online (Sandbox Code Playgroud)\n

这是代码(我不认为这里有什么问题)

\n
@Module\n@InstallIn(ActivityComponent::class)\nobject PermissionModule {\n\n    @ExperimentalCoroutinesApi\n    @Provides\n    @ActivityScoped\n    fun providePermissionsHelper(\n        @ActivityContext context: Context,\n    ) = PermissionsUtils(context)\n}\n
Run Code Online (Sandbox Code Playgroud)\n
@HiltViewModel\n@ExperimentalCoroutinesApi\nclass FileViewModel @Inject constructor(\n    private val class1: Class1,\n    private val class2: Class2,\n    private val class3: Class3,\n    private val permissionsUtils: PermissionsUtils //Here\'s the one I\'m injecting\n)\n
Run Code Online (Sandbox Code Playgroud)\n

我的猜测:它告诉我无法注入 ActivityComponent,因为 FileViewModel 被注入到 ActivityRetainedComponent/SingletonComponent/ViewModelComponent 中,因为提供给 viewmodel 的其他依赖项安装在该组件中?

\n

问题:这里到底发生了什么?我缺少什么以及使用 ActivityComponent 有什么解决方案吗?我真的需要@ActivityContext那堂课!

\n

编辑:当我更改为@InstallIn(ActivityRetainedComponent::class)并将上下文更改为@ApplicationContext context: Context时,这有效,请注意,它适用于 SingletonComponent/ViewModelComponent/ActivityRetainedComponent,这是有道理的。但我仍然不知道如何让它发挥作用@ActivityComponent

\n

编辑2:我得出的结论是不可能的,因为您在 ViewModel 中安装并且与ViewModel 一起使用的组件是 Singleton/ActivityRetained/ViewModel,所以没有办法注入ActivityContextViewModel 因为它需要该组件@ActivityComponent,这是ViewModelComponent 下面 1 级。

\n

来源: https: //dagger.dev/hilt/components#fn :1

\n

小智 18

因此无法在 ViewModel 中注入 ActivityContext,因为它需要组件 @ActivityComponent,而该组件比 ViewModelComponent 低 1 级。

你说对了。

从生命周期的角度考虑 Dagger/Hilt 组件(和范围)。在 Android 中, aViewModel的生命周期比其包含的Activity或更长Fragment。这就是这门课的全部意义,只是名字很不幸。将它们视为RetainedInstance或可能会有所帮助AnObjectThatSurvivesActivityConfigurationChanges。是的,这些不像 那样吸引人ViewModel

如果您将一个短期对象(the Activity)注入到一个长期对象(the ViewModel)中,后者将保留对前者的引用。这是内存泄漏 -Activity它及其包含的所有内容(例如视图、位图)仍然保留在内存中,即使不再使用。如果有其中几个,您就会面临OutOfMemoryError.

然而,相反的方式——即将长寿命的对象注入短寿命的对象中——是安全的。这就是为什么你让它与Singleton//组件ActivityRetained一起工作ViewModel

Hilt 的组件层次结构使您更难造成内存泄漏。所有这些都发生在编译时,与基于运行时的解决方案相比,这可以为您提供更快的反馈。比你的用户通过崩溃发现要好得多!