为什么我不能直接在 Android Studio 中使用 ViewModel 中的 State<T> ?

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

代码 A 来自此处的官方示例项目。

定义InterestsViewModeluiStateas ,并在 Composable 函数中将StateFlow其转换为State<T>by 。collectAsState()rememberTabContent

我很奇怪为什么作者不直接在中 定义uiState为,所以我写了代码B。State<T>InterestsViewModel

代码B可以编译,并且可以运行,但是屏幕上没有任何显示,代码B有什么问题?

代码A

data class InterestsUiState(
    val topics: List<InterestSection> = emptyList(),
    val people: List<String> = emptyList(),
    val publications: List<String> = emptyList(),
    val loading: Boolean = false,
)

class InterestsViewModel(
    private val interestsRepository: InterestsRepository
) : ViewModel() {

    // UI state exposed to the UI
    private val _uiState = MutableStateFlow(InterestsUiState(loading = true))
    val uiState: StateFlow<InterestsUiState> = _uiState.asStateFlow()
    ...
    init {
        refreshAll()
    }

    
    private fun refreshAll() {
        _uiState.update { it.copy(loading = true) }

        viewModelScope.launch {
             ...
            // Wait for all requests to finish
            val topics = topicsDeferred.await().successOr(emptyList())
            val people = peopleDeferred.await().successOr(emptyList())
            val publications = publicationsDeferred.await().successOr(emptyList())

            _uiState.update {
                it.copy(
                    loading = false,
                    topics = topics,
                    people = people,
                    publications = publications
                )
            }
        }
    }
 
}


@Composable
fun rememberTabContent(interestsViewModel: InterestsViewModel): List<TabContent> {
    // UiState of the InterestsScreen
    val uiState by interestsViewModel.uiState.collectAsState()
    ... 
    return listOf(topicsSection, peopleSection, publicationSection)
}


@Composable
fun InterestsRoute(
    interestsViewModel: InterestsViewModel,
    isExpandedScreen: Boolean,
    openDrawer: () -> Unit,
    scaffoldState: ScaffoldState = rememberScaffoldState()
) {
    val tabContent = rememberTabContent(interestsViewModel)
    val (currentSection, updateSection) = rememberSaveable {
        mutableStateOf(tabContent.first().section)
    }

    InterestsScreen(
        tabContent = tabContent,
        currentSection = currentSection,
        isExpandedScreen = isExpandedScreen,
        onTabChange = updateSection,
        openDrawer = openDrawer,
        scaffoldState = scaffoldState
    )
}
Run Code Online (Sandbox Code Playgroud)

代码B

data class InterestsUiState(
    val topics: List<InterestSection> = emptyList(),
    val people: List<String> = emptyList(),
    val publications: List<String> = emptyList(),
    var loading: Boolean = false,
)


class InterestsViewModel(
    private val interestsRepository: InterestsRepository
) : ViewModel() {
    
    // UI state exposed to the UI
    private var _uiState by mutableStateOf (InterestsUiState(loading = true))
    val uiState: InterestsUiState = _uiState

    ...
    
    init {
        refreshAll()
    }

    private fun refreshAll() {
        _uiState.loading = true

        viewModelScope.launch {
           ...
            _uiState = _uiState.copy(
                    loading = false,
                    topics = topics,
                    people = people,
                    publications = publications
                )
        }
    }

}

@Composable
fun rememberTabContent(interestsViewModel: InterestsViewModel): List<TabContent> {
    // UiState of the InterestsScreen
    val uiState = interestsViewModel.uiState
    ...
    return listOf(topicsSection, peopleSection, publicationSection)
}
Run Code Online (Sandbox Code Playgroud)

Arp*_*kla 6

uiState在可组合项中使用的val uiState: InterestsUiState = _uiState不是状态,因此不会响应更改。InterestsUiState它只是用当前值初始化的正常值_uiState。要使其工作,您只需公开 的 getter 即可_uiState

var uiState by mutableStateOf (InterestsUiState(loading = true))
    private set
Run Code Online (Sandbox Code Playgroud)

现在uiState只能从 ViewModel 内部进行修改,并且当您在 Composable 中使用它时,只要值发生uiState变化,就会发生重组。