一般来说,我知道每个屏幕定义多个 ViewModel 是一种不好的做法。然而,对于特殊用例,我发现它很有用。
例如,让我们考虑一个显示网络状态的 StatusBar Composable。通过 Hilt 注入将 ViewModel 封装在 Composable 中,使其可以在每个屏幕中重用,而不会用网络状态相关的东西“污染”屏幕 ViewModel。
但是,这会破坏屏幕预览,因为 Android Studio 中的预览不适用于 ViewModel。
那么,这是一种不好的做法吗?使用该可组合项重写每个屏幕的每个 ViewModel 中的逻辑会更好吗?
将以下代码视为我所指内容的示例。
// ViewModel.kt
@HiltViewModel
class OfflineStatusBarViewModel @Inject constructor(
networkState: NetworkState,
) : ViewModel() {
val isOffline = networkState.isAvailable
.map { !it }
.stateIn(viewModelScope, WhileUiSubscribed, false)
}
// StatusBar.kt
@Composable
fun OfflineStatusBar(
modifier: Modifier = Modifier,
viewModel: OfflineStatusBarViewModel = hiltViewModel()
) {
val isVisible by viewModel.isOffline.collectAsState()
if (isVisible) {
OfflineIndicator(modifier = modifier)
}
}
为每个子可组合子元素定义一个 ViewModel(即使带有柄)通常被认为是一种“不好的做法”。 ViewModel 通常负责管理 UI 相关的状态和业务逻辑。
子可组合项应该关注显示 UI 元素,而不是管理状态或业务逻辑。
更好的方法是将必要的
数据和回调
从父可组合项传递到子可组合项。这可以通过使用状态提升或将数据和回调作为参数传递给子可组合项来完成。这将使可组合项更加可重用和可测试,并且还有助于提高性能。因此,为每个可组合项拥有一个 ViewModel 会使代码库更加复杂且难以维护。它还可能导致逻辑和数据的重复,因为不同的 ViewModel 最终可能会管理类似的信息。
此外,如果您没有正确配置 Hilt,则每次可组合项重新组合时都会重新创建它。这可能会
导致性能问题
,尤其是在 ViewModel 执行大量工作的情况下。