我有一个名为ParentScreen
的可组合对象和一个名为ParentViewModel
的ViewModel
。在ParentViewModel
中,我从我的存储库中收集一个值。
class MyRepo @Inject constructor() {
fun getParentData() = System.currentTimeMillis().toString() // some dummy value
}
@HiltViewModel
class ParentViewModel @Inject constructor(
myRepo: MyRepo
) : ViewModel() {
private val _parentData = MutableStateFlow("")
val parentData = _parentData.asStateFlow()
init {
val realData = myRepo.getParentData()
_parentData.value = realData
}
}
@Composable
fun ParentScreen(
parentViewModel: ParentViewModel = hiltViewModel()
) {
val parentData by parentViewModel.parentData.collectAsState()
ChildWidget(parentData = parentData)
}
在ParentScreen
组合中,我有一个ChildWidget
组合,它有自己的ViewModel
,名为ChildViewModel
。
@HiltViewModel
class ChildViewModel @AssistedInject constructor(
@Assisted val parentData: String
) : ViewModel() {
@AssistedFactory
interface ChildViewModelFactory {
fun create(parentData: String): ChildViewModel
}
init {
Timber.d("Child says data is $parentData ")
}
}
@Composable
fun ChildWidget(
parentData: String,
childViewModel: ChildViewModel = hiltViewModel() // How do I supply assisted injection factory here?
) {
// Code omitted
}
现在,我想在ChildViewModel
的构造函数中获取parentData
。
问题
- 如何将
ChildViewModelFactory
提供给Navigation Compose的hiltViewModel
方法? - 如果这不可能,那么将对象从父组合注入到子组合的
ViewModel
的最合适的方法是什么?如何像下面这样创建lateinit
属性和init
方法?
@HiltViewModel
class ChildViewModel @Inject constructor(
) : ViewModel() {
lateinit var parentData: Long
fun init(parentData: Long){
if(this::parentData.isInitialized) return
this.parentData = parentData
}
}
1条答案
按热度按时间ukdjmx9f1#
您可以使用
EntryPointAccessors
(来自Hilt)和View Model库中的ViewModelProvider.Factory
来完成此操作。在我的sample app中,
BookFormScreen
使用的是BookFormViewModel
,视图模型需要根据上一个屏幕传递的bookId
加载一本书。我是这样做的:注意,我没有使用
@HiltViewModel
,provideFactory
将用于提供一个工厂来创建这个视图模型。然后,为入口点定义
ViewModelFactoryProvider
:现在,您需要定义一个可组合的函数来使用这个工厂提供视图模型。
如果你使用的是导航库,你可以在这个函数中添加
ViewModelStoreOwner
参数,并在viewModel()
函数调用中使用它。对于这个参数,你可以传递NavBackStackEntry
对象,这样,视图模型的作用域就会被限制到那个特定的回栈条目。最后,您可以在组合中使用视图模型。