假设我有一个带有功能模块的多模块 Jetpack Compose 项目,并且我想将一些对象实例的范围限制到功能生命周期。例如,我想将
AuthRepo
实例的范围限定为 AuthFeature
生命周期,并在用户登录后立即将其从内存中删除。我们还假设我的功能由几个可组合的屏幕组成。
所以,我的
MainActivity
看起来像这样:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
...
NavHost(navController = navController, startDestination = *AuthFeature graph*) {
navigation(*AuthFeature graph*) {
composable(*First Screen*) { backStackEntry ->
val authGraphEntry = *get authGraphEntry*
val vm = hiltViewModel<AuthViewModel>(authGraphEntry)
...
}
composable(*Second Screen*) { backStackEntry ->
val authGraphEntry = *get authGraphEntry*
val vm = hiltViewModel<AuthViewModel>(authGraphEntry)
...
}
}
*Other feature graph with multiple screens*
}
}
在这种情况下,没有问题:
AuthViewModel
(这两个屏幕都很常见)的范围仅限于 AuthFeature
图,我可以在注入 @ViewModelScoped
时使用 Hilt 的 AuthRepo
注释。因此 AuthViewModel
将在导航到其他功能(弹出到根)后被销毁,并且 AuthRepo
也将被销毁。
当我决定为每个屏幕创建一个 ViewModel 时,问题就出现了。第一个屏幕和第二个屏幕考虑使用相同的
AuthRepo
实例,但是用 AuthRepo
注释 @ViewModelScoped
会导致创建 AuthRepo
的两个实例,因为我有 2 个 ViewModel。使用 @Singleton
对其进行注释会导致为整个应用程序创建一个实例,该实例在导航到另一功能后不会被删除。
我想出了两种方法来解决这个问题:
将每个功能包含在活动中并使用
@ActivityRetainedScoped
。但是我想在我的项目中使用 SingleActivity 模式,所以这个解决方案对我来说无效。
使用 Dagger 及其自定义范围。但我希望有一个更简单的解决方案,无需手动组件生命周期处理,以保持代码整洁且不易出错。
另一方面,我不想为每个功能留下 1 个 ViewModel,因为有一天它可能会增长到大量代码行。有任何想法吗?如果我的一些说法有错误,请纠正我。
Hilt 的目的是拥有一组有限的范围,适合大多数用例,但您的特定需求需要使用 Dagger 自定义范围,正如您已经猜到的那样。