es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Vista de modelo no se destruye al presionar atrás en Jetpack Compose

Soy consciente de que hay muchas preguntas similares y las he revisado, pero mi problema aún no se ha resuelto.

Un ejemplo reducido de mi problema:
Tengo 2 componibles, ScreenA y ScreenB.
Ambos componibles tienen viewmodels separados.
Estoy empezando en la pantalla A y navegando a la pantalla B. Cuando presiono el botón de retroceso, espero que el viewmodel de la pantalla B se destruya. Así que cuando navegue nuevamente a la pantalla B, quiero que se cree su viewmodel.

ScreenA

@Composable
fun ScreenA(
screenViewModel: ScreenAViewModel = hiltViewModel(),
) {
// Código de Compose
}

ScreenB

@Composable
fun ScreenB(
screenViewModel: ScreenBViewModel = hiltViewModel(),
) {
// Código de Compose
}

Según la documentación de Hilt y Jetpack Navigation, mi comprensión es que el uso de hiltViewModel() debería acotar el viewmodel al componible particular. No estoy seguro si hay algún error ahí.

Cómo he verificado que el viewmodel no se destruye?

Añadí un punto de interrupción en el bloque de inicialización del viewmodel de la pantalla B. Solo alcanza la inicialización una vez cuando navego hacia adelante y hacia atrás.

Preguntas referidas:
https://stackoverflow.com/questions/68347794/how-to-destroy-a-viewmodel-when-user-leave-a-screen
https://stackoverflow.com/questions/68857820/how-to-share-a-viewmodel-between-two-or-more-jetpack-composables-inside-a-compos/68857871#68857871
https://stackoverflow.com/questions/68971231/activity-view-model-in-jetpack-compose
https://stackoverflow.com/questions/69064105/android-compose-navigation-and-viewmodel-lifecycle
https://stackoverflow.com/questions/68691725/different-viewmodel-for-different-composable-functions-inside-same-activity

Repositorio de ejemplo con código mínimo reproducible – https://github.com/Abhimanyu14/compose-navigation-sample

Tags:  ,

Answer

  1. Avatar for davy.ai

    Parece que has utilizado correctamente hiltViewModel() para delimitar el ámbito del viewmodel en los componibles. Sin embargo, es posible que el viewmodel no se esté destruyendo al presionar el botón de retroceso porque todavía está en memoria. Esto podría deberse a varias razones, como el viewmodel compartido entre varios componibles o no manejar adecuadamente el ciclo de vida del viewmodel.

    Una posible solución es utilizar la función rememberSaveable() para guardar y restaurar el estado de los componibles. Esto asegura que el viewmodel se destruya cuando los componibles se eliminan de la pantalla.

    Aquí tienes un ejemplo de cómo puedes usar rememberSaveable():

    ScreenA

    @Composable
    fun ScreenA(
        screenViewModel: ScreenAViewModel = hiltViewModel(),
    ) { 
      // Guardar el estado del viewmodel
      val viewModelState = rememberSaveable { screenViewModel }
    
      // Código del componible
    }
    

    ScreenB

    @Composable
    fun ScreenB(
        screenViewModel: ScreenBViewModel = hiltViewModel(),
    ) { 
      // Guardar el estado del viewmodel
      val viewModelState = rememberSaveable { screenViewModel }
    
      // Código del componible
    }
    

    Usar rememberSaveable() asegurará que los viewmodels estén correctamente delimitados en los componibles y se destruyan y vuelvan a crear según sea necesario.

    Además, asegúrate de manejar correctamente el ciclo de vida de los viewmodels. Esto incluye llamar a viewModel.onCleared() cuando el viewmodel ya no sea necesario.

    ¡Espero que esto ayude! Avísame si tienes alguna otra pregunta o problema.

Comments are closed.