一般来说,我知道在每个屏幕上定义多个视图模型是一种糟糕的做法.然而,对于特殊的用例,我发现它很有用.

例如,让我们考虑一个显示网络状态的StatusBar Composable.通过Hilt注入将ViewModel封装在Composable中,使其在每个屏幕上都可以重用,而不会用网络状态相关的东西"污染"屏幕ViewModel.

然而,这会 destruct 屏幕预览,因为Android Studio中的预览不能与ViewModel一起使用.

那么,这是一种糟糕的做法吗?使用该Composable重写每个屏幕的每个视图模型中的逻辑会更好吗?

请考虑以下代码作为我所指的示例.

// 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)
    }
}

推荐答案

通常被认为是bad practicedefine a ViewModel for every child composable even with hilt.ViewModel通常负责管理UI相关的状态和业务逻辑.
子组合应该关注显示UI元素,而不是管理状态或业务逻辑.
better approach is将必要的data and callbacks从父组合传递到子组合.这可以对子组合物进行using state hoisting or by passing the data and callbacks as parameters.这将使可组合more reusable and testable,它也将有助于improve performance.
因此, for each 可组合对象提供ViewModel会使代码库更加复杂和难以维护.它还可能导致逻辑和数据的重复,因为不同的ViewModel最终可能会管理类似的信息.
如果为you don't config the Hilt correctly,则每次重新组合组合对象时都会重新创建它.这可能是cause performance issues,特别是如果ViewModel正在做很多工作.

这是一篇由谷歌 compose 的关于100的精彩文章,一定要读一读.

Android相关问答推荐

fillMaxHeight中的分数在列内不起作用(android jetpack compose)

我如何剪裁一个可由另一个合成的

看不到选项菜单栏

在 Bash 脚本中使用 XMLLINT 解析 XML 单元测试文件,并将其放入数组中以表示成功和失败

Camera2 将图像从 ImageReader 传递到 MediaRecorder

布局可组合项如何具有可测量和约束参数?

闪屏 API 无法在 Android 12 上运行(API 31、32)

Android Studio:按下前缀键:切换 Logcat 格式

Jetpack compose :使用 rememberSaveable 时未应用待处理的合成

在 Kotlin 中设置 startActivity() 时类型不匹配

如何在 BottomBar jetpack compose 中删除选定的椭圆项目 colored颜色

Compose `Icons.Outlined.Star` 没有概述

我的 react native 项目的发布签名 apk 没有在设备中打开,而且它创建的尺寸非常小

并行运行两个挂起函数并在第一个返回时返回

构成material 3 中的分隔符

如何让用户与任意应用程序共享文件?

如何在 flow.stateIn() 之后从流中的另一个函数发出emits ?

即使我在单选按钮上明确设置了选中状态,RecyclerView 中的单选按钮也会随机取消选中

媒体播放器在状态 0 中调用,错误 (-38,0)

如何在 Eclipse 中打开现有项目