Compose : State Part.2

Skele·2024년 6월 3일
0

Android

목록 보기
9/15

StateFlow

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

collectAsStateWithLifecycle

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()

Side-Effect

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 )

How to safely call suspend functions in composable function?


LaunchedEffect

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.

rememberUpdatedState

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.

profile
Tireless And Restless Debugging In Source : TARDIS

0개의 댓글