Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

467
Visualizações
How to .collectAsState() from a StateFlow using repeatOnLifecycle() in a @Composable?

I'm trying to follow the official guidelines to migrate from LiveData to Flow/StateFlow with Compose, as per these articles:

A safer way to collect flows from Android UIs

Migrating from LiveData to Kotlin’s Flow

I am trying to follow what is recommended in the first article, in the Safe Flow collection in Jetpack Compose section near the end.

In Compose, side effects must be performed in a controlled environment. For that, use LaunchedEffect to create a coroutine that follows the composable’s lifecycle. In its block, you could call the suspend Lifecycle.repeatOnLifecycle if you need it to re-launch a block of code when the host lifecycle is in a certain State.

I have managed to use .flowWithLifecycle() in this way to make sure the flow is not emmiting when the app goes to the background:

@Composable
fun MyScreen() {

    val lifecycleOwner = LocalLifecycleOwner.current

    val someState = remember(viewModel.someFlow, lifecycleOwner) {
        viewModel.someFlow
            .flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
            .stateIn(
                scope = viewModel.viewModelScope,
                started = SharingStarted.WhileSubscribed(5000),
                initialValue = null
            )
    }.collectAsState()

}

I find this very "boilerplatey" -there must be something better. I would like to have StateFlow in the ViewModel, instead of Flow that gets converted to StateFLow in the @Composable, and use .repeatOnLifeCycle(), so I can use multiple .collectAsState() with less boilerplate.

When I try to use .collectAsState() inside a coroutine (LaunchedEffect), I obviously get an error about .collectAsState() having to be called from the context of @Composable function.

How can I achieve similar functionality as with .collectAsState(), but inside .repeatOnLifecycle(). Do I have to use .collect() on the StateFlow and then wrap the value with State? Isn't there anything with less boilerplate than that?

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

After reading a few more articles, including

Things to know about Flow’s shareIn and stateIn operators

repeatOnLifecycle API design story

I am becoming more convinced of using .flowWithLifecycle() in this way instead of repeatOnLifecycle() + produceState(). I just made this extension function to alleviate the boilerplate when collecting a flow as State from a @Composable:

@Composable
fun <T> Flow<T>.flowWithLifecycleStateInAndCollectAsState(
    scope: CoroutineScope,
    initial: T? = null,
    context: CoroutineContext = EmptyCoroutineContext,
): State<T?> {
    val lifecycleOwner = LocalLifecycleOwner.current
    return remember(this, lifecycleOwner) {
        this
            .flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
            .stateIn(
                scope = scope,
                started = SharingStarted.WhileSubscribed(5000),
                initialValue = initial
            )
    }.collectAsState(context)
}

This would then be used like this in a @Composable:

@Composable
fun SomeScreen() {

//...

    val someState = viewModel.someFlow
        .flowWithLifecycleStateInAndCollectAsState(
            scope = viewModel.viewModelScope  //or the composable's scope
        )

//...

}

I will mark this as accepted solution in case it helps someone else, unless someone lets me know of a better way in the next few days.

over 4 years ago · Santiago Trujillo Relatório

0

Building upon OP's answer, it can be a bit more light-weight by not going through StateFlow internally, if you don't care about the WhileSubscribed(5000) behavior.

@Composable
fun <T> Flow<T>.toStateWhenStarted(initialValue: T): State<T> {
    val lifecycleOwner = LocalLifecycleOwner.current
    return produceState(initialValue = initialValue, this, lifecycleOwner) {
        lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            collect { value = it }
        }
    }
}
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda