Concepts and Jetpack Compose implementation
The role of the UI is to display the application data on the screen and also to serve as the primary point of user interaction. Whenever the data changes, either due to user interaction (like pressing a button) or external input (like a network response), the UI should update to reflect those changes. Effectively, the UI is a visual representation of the application state as retrieved from the data layer.
However, the application data you get from the data layer is usually in a different format than the information you need to display. For example, you might only need part of the data for the UI, or you might need to merge two different data sources to present information that is relevant to the user. Regardless of the logic you apply, you need to pass the UI all the information it needs to render fully. The UI layer is the pipeline that converts application data changes to a form that the UI can present and then displays it.
Expose UI state
After you define your UI state and determine how you will manage the production
of that state, the next step is to present the produced state to the UI. Because
you're using UDF to manage the production of state, you can consider the
produced state to be a stream—in other words, multiple versions of the state
will be produced over time. As a result, you should expose the UI state in an
observable data holder like LiveData or StateFlow. The reason for this is so
that the UI can react to any changes made in the state without having to
manually pull data directly from the ViewModel. These types also have the
benefit of always having the latest version of the UI state cached, which is
useful for quick state restoration after configuration changes.
class NewsViewModel(...) : ViewModel() {
val uiState: StateFlow<NewsUiState> = …
}
A common way of creating a stream of UiState is by exposing a backing mutable
stream as an immutable stream from the ViewModel—for example, exposing a
MutableStateFlow<UiState> as a StateFlow<UiState>.
class NewsViewModel(...) : ViewModel() {
private val _uiState =