当我使用 Android Jetpack Compose 时,如何在 ViewModel 中设计 UI 状态类?

Hel*_*oCW 5 android kotlin android-jetpack-compose

我希望在 ViewModel 中设计 UI 状态类,以便在状态更改时启动 UI 重组。

我读过一些示例项目,例如 https://github.com/android/compose-sampleshttps://github.com/android/architecture-samples

我发现这些示例项目都是用Code A的方式设计UI状态类的,我不明白Code A的好处。

你知道我要在代码A中创建很多私有变量如 private val selectedCategoryprivate val categories,并且 combine( categories, selectedCategory ) { categories, selectedCategory ->...}一一编写。如果结构data class HomeViewState(...) 改变了,我就必须到处改变其他代码。

我不知道为什么人们不使用代码B,我认为它是示例,并且它适应变化data class HomeViewState(...),代码B中这种方法的缺点是什么?

代码A

class HomeViewModel(
) : ViewModel() {

    private val selectedCategory = MutableStateFlow(HomeCategory.Discover)
    private val categories = MutableStateFlow(HomeCategory.values().asList())

    private val _state = MutableStateFlow(HomeViewState())
    val state: StateFlow<HomeViewState>
        get() = _state

    init {
        viewModelScope.launch {
            combine(
                categories,
                selectedCategory

            ) { categories, selectedCategory ->
                HomeViewState(
                    homeCategories = categories,
                    selectedHomeCategory = selectedCategory
                )
            }.catch { throwable ->
                // TODO: emit a UI error here. For now we'll just rethrow
                throw throwable
            }.collect {
                _state.value = it
            }
        }
    }

    fun onHomeCategorySelected(category: HomeCategory) {
        selectedCategory.value = category
    }
}

enum class HomeCategory {
    Library, Discover
}

data class HomeViewState(
    val selectedHomeCategory: HomeCategory = HomeCategory.Discover,
    val homeCategories: List<HomeCategory> = emptyList()
)
Run Code Online (Sandbox Code Playgroud)

代码B

class HomeViewModel(
) : ViewModel() {

    private val _state = MutableStateFlow(HomeViewState())
    val state: StateFlow<HomeViewState>
        get() = _state

    init {
        viewModelScope.launch {
            _state.update { it.copy(
                selectedHomeCategory= HomeCategory.Discover,
                homeCategories = HomeCategory.values().toList()
            ) }
        }
    }

    fun onHomeCategorySelected(category: HomeCategory) {
        _state.update { it.copy(selectedHomeCategory = category) }      
    }
}

enum class HomeCategory {
    Library, Discover
}

data class HomeViewState(
    val selectedHomeCategory: HomeCategory = HomeCategory.Discover,
    val homeCategories: List<HomeCategory> = emptyList()
)
Run Code Online (Sandbox Code Playgroud)

Eli*_*ber 0

对于你的情况,我也会选择代码 B。我可以想到几种情况我会选择选项A;要么我需要访问ViewModel 内其他函数中的selectedCategory 和变量,要么是像这样的情况,例如初始化不仅传递一个值,而且调用/观察 repo 函数(更干净的代码,更容易调试)categories