使用 Compose UI 时如何为每个列表项创建单独的 ViewModel?
How to create separate ViewModels per list item when using Compose UI?
我正在开发一个交易应用程序。我需要列出用户股票及其价值(盈利或亏损)以及投资组合的总价值。
对于馆藏列表,在 MVP 架构中,我会为每个列表项创建一个演示者,但对于这个应用程序,我决定使用 MVVM(Compose、ViewModels 和 Hilt)。我的第一个想法是为每个列表项创建一个不同的 ViewModel。我在可组合方法签名中使用 hiltViewModel()
来创建我的 ViewModel 的实例,但这总是给我相同的实例,这不是我想要的。使用 MVVM 体系结构时,我尝试做的是正确的方法还是我应该使用单个 ViewModel?你知道我可以看看的任何项目吗?下图是我实际屏幕的超级简化,每个单元格都很复杂,这就是为什么我想为每个单元格使用不同的 ViewModel。非常欢迎任何建议。
很遗憾,HiltViewModelFactory
不是 KeyedFactory
。所以到目前为止,它不支持具有多个实例的相同 viewModel。
用于 Compose 中的键控视图模型的 Hilt doesn't support keyed view models. There's a feature request,但我们必须等到 Hilt 支持它。
这里有一个关于如何绕过它的 hacky 解决方案。
您可以创建一个可以与键一起使用的普通视图模型,并通过 Hilt 视图模型将注入传递给此视图模型:
class SomeInjection @Inject constructor() {
val someValue = 0
}
@HiltViewModel
class InjectionsProvider @Inject constructor(
val someInjection: SomeInjection
): ViewModel() {
}
class SomeViewModel(private val injectionsProvider: InjectionsProvider) : ViewModel() {
val injectedValue get() = injectionsProvider.someInjection.someValue
var storedValue by mutableStateOf("")
private set
fun updateStoredValue(value: String) {
storedValue = value
}
}
@Composable
fun keyedViewModel(key: String) : SomeViewModel {
val injectionsProvider = hiltViewModel<InjectionsProvider>()
return viewModel(
key = key,
factory = object: ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return SomeViewModel(injectionsProvider) as T
}
}
)
}
@Composable
fun TestScreen(
) {
LazyColumn {
items(100) { i ->
val viewModel = keyedViewModel("$i")
Text(viewModel.injectedValue.toString())
TextField(value = viewModel.storedValue, onValueChange = viewModel::updateStoredValue)
}
}
}
我正在开发一个交易应用程序。我需要列出用户股票及其价值(盈利或亏损)以及投资组合的总价值。
对于馆藏列表,在 MVP 架构中,我会为每个列表项创建一个演示者,但对于这个应用程序,我决定使用 MVVM(Compose、ViewModels 和 Hilt)。我的第一个想法是为每个列表项创建一个不同的 ViewModel。我在可组合方法签名中使用 hiltViewModel()
来创建我的 ViewModel 的实例,但这总是给我相同的实例,这不是我想要的。使用 MVVM 体系结构时,我尝试做的是正确的方法还是我应该使用单个 ViewModel?你知道我可以看看的任何项目吗?下图是我实际屏幕的超级简化,每个单元格都很复杂,这就是为什么我想为每个单元格使用不同的 ViewModel。非常欢迎任何建议。
很遗憾,HiltViewModelFactory
不是 KeyedFactory
。所以到目前为止,它不支持具有多个实例的相同 viewModel。
用于 Compose 中的键控视图模型的 Hilt doesn't support keyed view models. There's a feature request,但我们必须等到 Hilt 支持它。
这里有一个关于如何绕过它的 hacky 解决方案。
您可以创建一个可以与键一起使用的普通视图模型,并通过 Hilt 视图模型将注入传递给此视图模型:
class SomeInjection @Inject constructor() {
val someValue = 0
}
@HiltViewModel
class InjectionsProvider @Inject constructor(
val someInjection: SomeInjection
): ViewModel() {
}
class SomeViewModel(private val injectionsProvider: InjectionsProvider) : ViewModel() {
val injectedValue get() = injectionsProvider.someInjection.someValue
var storedValue by mutableStateOf("")
private set
fun updateStoredValue(value: String) {
storedValue = value
}
}
@Composable
fun keyedViewModel(key: String) : SomeViewModel {
val injectionsProvider = hiltViewModel<InjectionsProvider>()
return viewModel(
key = key,
factory = object: ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return SomeViewModel(injectionsProvider) as T
}
}
)
}
@Composable
fun TestScreen(
) {
LazyColumn {
items(100) { i ->
val viewModel = keyedViewModel("$i")
Text(viewModel.injectedValue.toString())
TextField(value = viewModel.storedValue, onValueChange = viewModel::updateStoredValue)
}
}
}