0

I am using compose navigation with single activity and no fragments.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MobileComposePlaygroundTheme {
                Surface(color = MaterialTheme.colors.background) {
                    val navController = rememberNavController()
                    NavHost(navController, startDestination = "main") {
                        composable("main") { MainScreen(navController) }
                        composable("helloScreen") { HelloScreen() }
                    }
                }
            }
        }
    }
}

@Composable
private fun MainScreen(navController: NavHostController) {
    val count = remember {
        Log.d("TAG", "inner remember, that is, initialized")
        mutableStateOf(0)
    }

    LaunchedEffect("fixedKey") {
        Log.d("TAG", "inner LaunchedEffect, that is, initialized")
    }

    Column {
        Spacer(modifier = Modifier.height(16.dp))
        Button(
            onClick = {
                count.value++
                Log.d("TAG", "count: ${count.value}")
            },
            modifier = Modifier.padding(8.dp)
        ) {
            Text(text = "Increase Count ${count.value}")
        }
        Button(
            onClick = { navController.navigate("helloScreen") },
            modifier = Modifier.padding(8.dp)
        ) {
            Text(text = "Go To HelloScreen")
        }
    }
}

@Composable
fun HelloScreen() {
    Log.d("TAG", "HelloScreen")
    Text("Hello Screen")
}

enter image description here

MainScreen -> HelloScreen -> back button -> MainScreen

After pop HelloScreen by back button, MainScreen restart composition from scratch. That is, not recomposition but initial composition. So remember and LaunchedEffect is recalculated.

I got rememberSaveable for maintaining states on this popping upper screen case. However how can I prevent re-execute LaunchedEffect? In addition, docs saying rememberSavable makes value to survive on configuration change but this is not the exact case.

I expected that LowerScreen is just hidden when UpperScreen is pushed, and LowerScreen reveal again when UpperScreen is popped, like old Android's onPause(), onResume(), etc. In Compose, is this not recommended?

ps. Lifecycle of Composable is not tied with ViewModel but with Activity It needs more care about initialization of ViewModel Why Compose team design like this? Can you recommend good architecture sample code?

wonpyohong
  • 344
  • 4
  • 7
  • 2
    this is expected behaviour. When screen disappears, it's removed from the view tree and all the resources are freed. You can use a view model - data stored inside will be saved in such case. Or you can save the data in any storage and read when screen appears. – Phil Dukhov Mar 19 '22 at 11:29
  • Thanks for answer about viewModel. Um.. let's change situation a little. Increase viewModel.count on UpperScreen -> pop UpperScreen -> push UpperScreen again -> count is not zero because viewModel is tied with Activity. How can I distinguish initialization point? I want to initialize only when pushed not when upper screen poped – wonpyohong Mar 19 '22 at 11:43
  • 1
    view model is tied to navigation route. each time you push a new one - a new view model will be created, unless it's saved(during pop) – Phil Dukhov Mar 19 '22 at 11:48
  • 1
    Oh.. I tested it again and confirmed you are right. I got it wrong. Thanks!!! – wonpyohong Mar 19 '22 at 12:06

0 Answers0