Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

470
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda