Home > Enterprise >  Will navController.navigate() cause Android recomposition when I use Compose?
Will navController.navigate() cause Android recomposition when I use Compose?

Time:12-28

The Code A is from the end branch of the official sample project

When I click the Tab of the UI, the App will show the corresponding UI, and the current Tab will be marked as a different style.

In Overview.name Tab UI page, if I click a account item, the code composable(Overview.name) {... onAccountClick = { name -> navigateToSingleAccount(navController, name) } will navigate it to composable( route = "$accountsName/{name}", ..) UI , and Accounts.name is marked as current Tab.

What make me confuse is why Android can make Accounts.name as current Tab, could you tell me? Will navController.navigate() cause Android recomposition? so is val currentScreen = RallyScreen.fromRoute(backstackEntry.value?.destination?.route) re-executed ?

Code A

@Composable
fun RallyApp() {
    RallyTheme {
        val allScreens = RallyScreen.values().toList()
        val navController = rememberNavController()
        val backstackEntry = navController.currentBackStackEntryAsState()
        val currentScreen = RallyScreen.fromRoute(backstackEntry.value?.destination?.route)

        Scaffold(
            topBar = {
                RallyTabRow(
                    allScreens = allScreens,
                    onTabSelected = { screen ->
                        navController.navigate(screen.name)
                    },
                    currentScreen = currentScreen
                )
            }
        ) { innerPadding ->
            RallyNavHost(navController, modifier = Modifier.padding(innerPadding))
        }
    }
}

@Composable
fun RallyNavHost(navController: NavHostController, modifier: Modifier = Modifier) {
    NavHost(
        navController = navController,
        startDestination = Overview.name,
        modifier = modifier
    ) {
        composable(Overview.name) {
           OverviewBody(
                onClickSeeAllAccounts = { navController.navigate(Accounts.name) },
                onClickSeeAllBills = { navController.navigate(Bills.name) },
                onAccountClick = { name ->
                    navigateToSingleAccount(navController, name)
                },
            )
        }

        composable(Accounts.name) {
            AccountsBody(accounts = UserData.accounts) { name ->
                navigateToSingleAccount(navController = navController, accountName = name)
            }
        }
        composable(Bills.name) {
           ...
        }


        val accountsName = Accounts.name
        composable(
            route = "$accountsName/{name}",
            arguments = listOf(
                navArgument("name") {
                    type = NavType.StringType
                }
            ),
            deepLinks = listOf(
                navDeepLink {
                    uriPattern = "rally://$accountsName/{name}"
                }
            ),
        ) { entry ->
            val accountName = entry.arguments?.getString("name")
            val account = UserData.getAccount(accountName)
            SingleAccountBody(account = account)
        }
    }
}

private fun navigateToSingleAccount(navController: NavHostController, accountName: String) {
    navController.navigate("${Accounts.name}/$accountName")
}


enum class RallyScreen(
    val icon: ImageVector,
) {
    Overview(
        icon = Icons.Filled.PieChart,
    ),
    Accounts(
        icon = Icons.Filled.AttachMoney,
    ),
    Bills(
        icon = Icons.Filled.MoneyOff,
    );

    companion object {
        fun fromRoute(route: String?): RallyScreen =
            when (route?.substringBefore("/")) {
                Accounts.name -> Accounts
                Bills.name -> Bills
                Overview.name -> Overview
                null -> Overview
                else -> throw IllegalArgumentException("Route $route is not recognized.")
            }
    }
}

CodePudding user response:

Yes, navigate() will definitely cause recomposition as the UI is getting re-created.

Yes, val currentScreen = RallyScreen.fromRoute(backstackEntry.value?.destination?.route) will be re-executed as backstackEntry is being observed as state and its value will change when you navigate. That's why the RallyApp composable will also get recomposed. So when it is executed again, currentScreen value will get updated.

  • Related