Jetpack compose: ¿cómo actualizo una pantalla cuando la aplicación vuelve al primer plano?

5 minutos de lectura

Avatar de usuario de William
Guillermo

Necesito actualizar automáticamente una pantalla de Redacción de Android cuando la aplicación vuelve al primer plano.

Tengo una que requiere permisos y servicios de ubicación.

Si el usuario ha desactivado alguno de estos, se dibuja una lista de los elementos que deben cambiarse. Cuando el usuario va a Configuración y la aplicación vuelve al primer plano, me gustaría que la lista se actualice para reflejar los cambios.

Estoy usando Redactar y Redactar navegación. He buscado y no puedo encontrar el equivalente del evento del ciclo de vida onResume que podría usarse para activar la actualización.

Cualquier idea sería recibida con gratitud ya que estoy perdido.

Avatar de usuario de JojoIV
Jojo IV

Se me ocurrió esto:

@Composable
fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) {
    val eventHandler = rememberUpdatedState(onEvent)
    val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
    
    DisposableEffect(lifecycleOwner.value) {
        val lifecycle = lifecycleOwner.value.lifecycle
        val observer = LifecycleEventObserver { owner, event ->
            eventHandler.value(owner, event)
        }

        lifecycle.addObserver(observer)
        onDispose {
            lifecycle.removeObserver(observer)
        }
    }
}

Parece funcionar bien. Pero puede haber algunos problemas en algunos casos, así que tenga cuidado.
También es posible que haya algún código redundante.

Uso:

OnLifecycleEvent { owner, event ->
    // do stuff on event
    when (event) {
        Lifecycle.Event.ON_RESUME -> { /* stuff */ }
        else                      -> { /* other stuff */ }
    }
}

  • Un ejemplo de cómo usar esto sería útil

    – SagaRock101

    1 de enero de 2022 a las 13:46

  • Por qué lifecycleOwner tiene que cambiar? ¿No es algo de solo lectura?

    – salida estándar

    4 de julio de 2022 a las 8:22

  • En producción, observamos algunos problemas de bucle en onResume(). es decir, sigue llamando al bloque Lifecycle.Event.ON_RESUME -> { /* cosas */ } en bucles

    – Boobalán

    7 de febrero a las 18:56

Avatar de usuario de Arsenio
Arsenio

mejoré un poco @JojoIV responda y lo hizo de uso plano sin devolución de llamada como observa LiveData en componer lo que @Abdelilah El Aissaoui contestada

@Composable
fun Lifecycle.observeAsState(): State<Lifecycle.Event> {
    val state = remember { mutableStateOf(Lifecycle.Event.ON_ANY) }
    DisposableEffect(this) {
        val observer = LifecycleEventObserver { _, event ->
            state.value = event
        }
        this@observeAsState.addObserver(observer)
        onDispose {
            this@observeAsState.removeObserver(observer)
        }
    }
    return state
}

y luego el uso

@Composable
fun SomeComposable() {
   val lifecycleState = LocalLifecycleOwner.current.lifecycle.observeAsState()
   val state = lifecycleState.value
   // or val lifecycleState by LocalLifecycleOwner.current.lifecycle.observeAsState()
  // will re-render someComposable each time lifecycleState will change
}

  • Esta respuesta fue útil cuando se usaba solo reanudar y pausar, pero no iniciar y detener.

    – Bam Bam

    8 de noviembre de 2022 a las 5:44

  • @bambam ¿por qué es eso?

    – Josué Rey

    17/11/2022 a las 21:50

  • Imprimir (el state antes del regreso) y (el event de LifecycleEventObserver) en el primer fragmento . En mi caso el primero solo llamaba RESUME y PAUSE. No estoy seguro, pero parece que hay una omisión al pasar por el estado de redacción en lugar de pasar el evento de inmediato. Si no se reproduce, haré más pruebas. @JoshuaKing

    – Bam Bam

    18 de noviembre de 2022 a las 2:39

ejemplo del sitio de google

@Composable
fun HomeScreen(
  lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
  onStart: () -> Unit, // Send the 'started' analytics event
  onStop: () -> Unit   // Send the 'stopped' analytics event
) {
    // Safely update the current lambdas when a new one is provided
    val currentOnStart by rememberUpdatedState(onStart)
    val currentOnStop by rememberUpdatedState(onStop)

    // If `lifecycleOwner` changes, dispose and reset the effect
    DisposableEffect(lifecycleOwner) {
        // Create an observer that triggers our remembered callbacks
        // for sending analytics events
        val observer = LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_START) {
                currentOnStart()
            } else if (event == Lifecycle.Event.ON_STOP) {
                currentOnStop()
            }
        }

        // Add the observer to the lifecycle
        lifecycleOwner.lifecycle.addObserver(observer)

        // When the effect leaves the Composition, remove the observer
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }

    /* Home screen content */
}

Descripción completa de cómo funciona en el sitio de Google
https://developer.android.com/jetpack/compose/side-effects#disposableeffect

Avatar de usuario de Abdelilah El Aissaoui
Abdelilah El Aissaoui

Edición 2: Hay un nueva edición tener esta función incluida en la API de Componer. Pensamiento aún no disponible (a partir de agosto de 2022)

Editar: Si desea una respuesta de redacción “pura”, consulte la respuesta de @JoJoIV

Respuesta:

Compose no es consciente de los cambios de estado como onPause o onResumedebe manejarlo utilizando los métodos de la actividad principal.

Un ejemplo sería un LiveData instancia en su actividad que se actualiza cada vez onResume se ejecuta y obsérvelo como un estado en su componente principal principal.

Echemos un vistazo al siguiente ejemplo:

class MainActivity : AppCompatActivity() {
    // Use whatever type your prefer/require, this is just an example
    private val exampleLiveData = MutableLiveData("")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            // Your main composable
            MyApplicationTheme {
                // Save the state into a variable otherwise it won't work
                val state = exampleLiveData.observeAsState()
                Log.d("EXAMPLE", "Recomposing screen - ${state.value}")

                Surface(color = MaterialTheme.colors.background) {
                    Greeting("Android")
                }
            }
        }
    }

    override fun onResume() {
        super.onResume()

        // Save whatever you want in your live data, this is just an example
        exampleLiveData.value = DateTimeFormatter.ISO_INSTANT.format(Instant.now())
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    MyApplicationTheme {
        Greeting("Android")
    }
}

Como puede ver en este ejemplo, tengo un LiveData propiedad en mi actividad que contiene una cadena. Cuando sea onResume se ejecuta, la propiedad se actualiza con la nueva marca de tiempo y se recompone el componible de observación.

Avatar de usuario de EunhaEonnie
EunhaEonnie

Cambié @ojoIV código a esto (si su código componible está en Actividad)

@Composable
fun ComponentActivity.LifecycleEventListener(event: (Lifecycle.Event) -> Unit) {
    val eventHandler by rememberUpdatedState(newValue = event)
    val lifecycle = this@LifecycleEventListener.lifecycle
    DisposableEffect(lifecycle) {
        val observer = LifecycleEventObserver { _, event ->
            eventHandler(event)
        }
        
        lifecycle.addObserver(observer)
        
        onDispose {
            lifecycle.removeObserver(observer)
        }
    }
}

uso

LifecycleEventListener(event = { lifecycleEvent ->
    when (lifecycleEvent ) {
        Lifecycle.Event.ON_CREATE -> {}
        Lifecycle.Event.ON_START -> {}
        Lifecycle.Event.ON_RESUME -> {}
        Lifecycle.Event.ON_PAUSE -> {}
        Lifecycle.Event.ON_STOP -> {}
        Lifecycle.Event.ON_DESTROY -> {}
        else -> return@LifecycleEventListener
    }
})

  • Lindo ! Gracias ! pero el enlace de abajo está muerto.

    – Mahdi Safarmohammadloo

    5 de junio de 2022 a las 13:16

  • Lindo ! Gracias ! pero el enlace de abajo está muerto.

    – Mahdi Safarmohammadloo

    5 de junio de 2022 a las 13:16

¿Ha sido útil esta solución?