An observable flow that emits state to the collectors.
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
// Backing property to avoid state updates from other classes
private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
// The UI collects from this StateFlow to get its state updates
val uiState: StateFlow<LatestNewsUiState> = _uiState
init {
viewModelScope.launch {
newsRepository.favoriteLatestNews
// Update View with the latest favorite news
// Writes to the value property of MutableStateFlow,
// adding a new element to the flow and updating all
// of its collectors
.collect { favoriteNews ->
_uiState.value = LatestNewsUiState.Success(favoriteNews)
}
}
}
}
// Represents different states for the LatestNews screen
sealed class LatestNewsUiState {
data class Success(val news: List<ArticleHeadline>): LatestNewsUiState()
data class Error(val exception: Throwable): LatestNewsUiState()
}
Collects state flow in life-cycle aware manner.
private val _datas = MutableStateFlow<List<DataModel>>(emptyList())
val datas : StateFlow<List<DataModel>> = _datas.asStateFlow()
val datas by viewModel.datas.collectAsStateWithLifecycle()
Change of the state in the app that happens outside the scope of a composable function. ( e.g. opening a new screen when tapping a button, showing a message when an app doesn't have internect connection, or calling the network )
Starts a life-cycle aware coroutine with composition's coroutine context. Coroutine will cancel when LaunchedEffect leaves the composition or key changes. On key change, coroutine cancels and restarts.
LaunchedEffect(key1 = someParameter) {
delay(...) // suspend function
...
}
Key can be variables, functions, or Unit.
@Composable
fun SomeComposable(callback: () -> Unit, modifier: Modifier = Modifier) {
Box(...) {
LaunchedEffect(key1 = Unit) {
delay(...) // suspend function
callback()
}
...
}
}
With Unit as a key, the coroutine will launch only once. But in this case, the callback parameter can change through recompositions, whereas callback invoked in LaunchedEffect is not updating.
A mutableStateOf that remembers its state and updates to new value on each recomposition.
@Composable
fun LandingScreen(callback: () -> Unit, modifier: Modifier = Modifier) {
Box(...) {
val currentCallback by rememberUpdatedState(newValue = callback)
LaunchedEffect(key1 = Unit) {
delay(...) // suspend function
currentCallback()
}
...
}
}
Using rememberUpdatedState with LaunchedEffect will guarantee to invoke the newest callback assigned on recent recomposition.