ViewModelComponent
是一个 Hilt 组件层次结构 (Component hierarchy) 中的一员,它遵循 ViewModel 的生命周期,并能够限定类型的做用域到此组件上。android
在 ViewModelComponent
添加到 Hilt 以前,ViewModel 类经过 ActivityRetainedComponent
建立和注入。所以,ViewModel 中的依赖项仅可使用未限定做用域、或是将做用域限定到 SingletonComponent
或 ActivityRetainedComponent
中,被全部 ViewModel 共享实例的类型。缓存
若是您的 App 每一个页面都仅为一个 Activity,上述内容并不会成为问题,由于此状况中将类型的做用域限定为 ActivityRetainedComponent
意味着每一个页面的 ViewModel 类都将得到该类型的不一样实例。然而,每一个页面仅为一个 Activity 并不适用于大多数 App。ide
此外,ActivityRetainedComponent
组件不会默认绑定 SavedStateHandle
。google
如今,您能够经过遵循 ViewModel 生命周期的 ViewModelComponent 组件来建立并注入 ViewModel。每个 ViewModel 实例持有不一样的 ViewModelComponent 实例,您可使用 @ViewModelScoped 注解,将类型的做用域限定到该组件上。spa
ViewModelComponent 在精简版 Hilt 组件层次结构中的位置
ViewModelComponent
继承自 ActivityRetainedComponent
,所以它的类型限定依赖于上层的 SingletonComponent
和 ActivityRetainedComponent
。除此以外,ViewModelComponent 还默认绑定了一个与 ViewModel 关联的 SavedStateHandle
。code
与其余组件相比,经过使用 @ViewModelScoped 将做用域绑定为 ViewModelComponent,并将其注入到 ViewModel 中,能够得到更好的灵活性和更精细的控制粒度。ViewModel 能够在配置更改中保存状态,而且其生命周期能够被 Activity、Fragment,甚至是 导航图 控制。component
可是,因为 ActivityComponent
和 FragmentComponent
不会在配置更改中保存状态,因此在某些状况下仍然有必要限定做用域到这些组件。另外,FragmentComponent
继承自 ActivityComponent
,使用多个 ViewModelComponent
没法实现相同的行为。继承
所以:接口
@ActivityRetainedScoped
注解。@ViewModelScoped
注解。@ActivityScoped
注解,若是须要将做用域限定为 Fragment 并实现上述行为,使用 @FragmentScoped
注解。您可使用该注解将一个类型的做用域限定为特定 ViewModel 的实例。ViewModel 及其依赖项以及他们的依赖都将注入相同的实例。生命周期
下面的示例中,LoginViewModel
以及 RegistrationViewModel
分别使用了被 @ViewModelScoped
注解的 UserInputAuthData
类型,使它们拥有不一样的状态。
@ViewModelScoped // 将类型的做用域限定为 ViewModel class UserInputAuthData( private val handle: SavedStateHandle //在 ViewModelComponent 中默认绑定 ) { /* 逻辑代码以及缓存数据*/ } class RegistrationViewModel( private val userInputAuthData: UserInputAuthData, private val validateUsernameUseCase: ValidateUsernameUseCase, private val validatePasswordUseCase: ValidatePasswordUseCase ) : ViewModel() { /* ... */ } class LoginViewModel( private val userInputAuthData: UserInputAuthData, private val validateUsernameUseCase: ValidateUsernameUseCase, private val validatePasswordUseCase: ValidatePasswordUseCase ) : ViewModel() { /* ... */ } class ValidateUsernameUseCase( private val userInputAuthData: UserInputAuthData, private val repository: UserRepository ) { /* ... */ } class ValidatePasswordUseCase( private val userInputAuthData: UserInputAuthData, private val repository: UserRepository ) { /* ... */ }
由于 UserInputAuthData
的做用域被限定为 ViewModel,RegistrationViewModel
和 LoginViewModel
将得到不一样的 UserInputAuthData
实例。然而,每一个 ViewModel 中没有限定做用域的 UseCase 依赖会与其 ViewModel 使用相同的 UserInputAuthData
实例。
和其余组件同样,您能够向 ViewModelComponent 中添加绑定。若是在上述代码片断中,ValidateUsernameUseCase 是一个接口,您能够这样通知 Hilt 使用哪一种实现:
@Module @InstallIn(ViewModelComponent::class) object UserAuthModule { @Provides fun provideValidateUsernameUseCase( userInputAuthData: UserInputAuthData, //做用域为 ViewModelComponent repository: UserRepository ): ValidateUsernameUseCase { return ValidateUsernameUseCaseImpl(userInputAuthData, repository) } }
ViewModelComponent
遵循 ViewModel 的生命周期,并能够将类型的做用域限定到此组件上。因为 ViewModel 的生命周期能够被 Activity、Fragment 甚至是 导航图 所控制,您能够根据须要将做用域限定到这些地方,来得到更大的灵活性和更精细的控制粒度。
请使用 @ViewModelScoped
将类型的做用域限定为 ViewModel。使用 @ActivityRetainedScoped
限定做用域,使同一界面的全部的 ViewModel 共享同一个类型的实例。