Home > Blockchain >  Navigate back to previous composable screen Lifecycle.Event.ON_CREATE event call again
Navigate back to previous composable screen Lifecycle.Event.ON_CREATE event call again

Time:06-17

My question is that when i navigate back/popup to previous composable screen Lifecycle.Event.ON_CREATE event call again. For example i have two composable screen, first show list of item and send one is detail screen of specific item. When i navigate back to list item screen. List item screen load(network call) again. Below is code test sample

Navigation Logic

val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home"){
  composable("home") {
    RememberLifecycleEvent(event = {
      Log.i("check","home event")
      // API Call
    })
 
    Column(
     modifier = Modifier
         .fillMaxSize(),
     verticalArrangement = Arrangement.Center,
     horizontalAlignment = Alignment.CenterHorizontally
    ) {
    Button(onClick = { navController.navigate("blur") }) {
      Text(text = "Blur")
      }
     } 
   }
   composable("blur") {
     RememberLifecycleEvent(event = {
          Log.i("check","blur event")
     })
   Column(
     modifier = Modifier
          .fillMaxSize(),
     verticalArrangement = Arrangement.Center,
     horizontalAlignment = Alignment.CenterHorizontally
   ) {
        Button(onClick = { navController.navigate("home") }) {
         Text(text = "Home")
        }
       }
     }
   }

Lifecycle Event Logic

@Composable
fun RememberLifecycleEvent(
  event: () -> Unit,
  lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
) {
  val state by rememberUpdatedState(newValue = event)
  DisposableEffect(lifecycleOwner) {
    val observer = LifecycleEventObserver { owner, event ->
        if (event == Lifecycle.Event.ON_CREATE) {
            state()
            Log.i("check","event = $event")
        }
    }
    lifecycleOwner.lifecycle.addObserver(observer)
    onDispose {
        lifecycleOwner.lifecycle.removeObserver(observer)
    }
  }
 }

I want to call api only first time in Lifecycle.Event.ON_CREATE event

CodePudding user response:

This is happening because when you navigate from A to B, the onDispose is called in A. Then, when you return to A from B, the DisposableEffect is called again and since the Activity is already in "resumed" state, the ON_CREATE event is sent again.

My suggestion is controlling this call in your view model since it is kept alive after you go to B from A.

CodePudding user response:

There are a few possibilities depending if you want to call the API once on every 'forward' navigation to your first screen or if you want to call the API just once based on some other criteria.

If former, you can either use a ViewModel and call the API from it when the ViewModel is created. If you use Hilt and call hiltViewModel() inside your Composable the ViewModel will be scoped to the lifecycle of the NavBackStackEntry of your NavHost.

But the same scope can also be achieved by simply using a rememberSaveable, since this will use the saveStateHandle from the NavBackStackEntry of your NavHost.

Another advantage is that both of the above options also ensure that the API won't be called again on orientation change and other configuration changes (when they are enabled).

// Just a sample (suspend) call
suspend fun someApi(): String {
    // ...
    return "some result"
}

val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home"){
  composable("home") {

    var apiCalled by rememberSaveable { mutableStateOf(false) }
    if (!apiCalled) {
        apiCalled = true
        // key = Unit is okay here, we only want to launch once when entering the composition
        LaunchedEffect(Unit) { 
            val result = runCatching {
                someApi()
            }
            if (result.isFailure) {
                // retry the api call? or report the error
            }
        }
    }

    // rest of your code ...
  }
}
  • Related