android / codelab-android-navigation

Apache License 2.0
634 stars 275 forks source link

Jetpack: composable in NavHost is recomposing again and again when navigating to another route #113

Open greatpuzzlex opened 3 years ago

greatpuzzlex commented 3 years ago

Navigation to another routes creates infinite loop of recomposition in navhost. Here is my code: jetpack navigation-compose : androidx.navigation:navigation-compose:2.4.0-alpha06

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        setContent {

            NavigationComposeTheme {

                // A surface container using the 'background' color from the theme

                Surface(color = MaterialTheme.colors.background) {

                    Navigation()

                }

            }

        }

    }

}

@Composable

fun Navigation(){

    val navigation  = rememberNavController()

    NavHost(navController = navigation, startDestination = "greeting"){

        composable("greeting", content = {

            Greeting(name = "hello", navigation)

        })

        composable("greeting2", content = {

            Greeting2(name = "Hii")

        })

    }

}

@Composable

fun Greeting(name: String, navigation: NavHostController) {

    Log.e("====111111====", name)

    Text(text = "Hello $name!")

    navigation.navigate("greeting2")

}

@Composable

fun Greeting2(name: String) {

    Log.e("====22222222====", name)

    Text(text = "Hii $name!")

}
ryanholden8 commented 2 years ago

You should only call navigate() as part of a callback and not as part of your composable itself, to avoid calling navigate() on every recomposition.

From: https://developer.android.com/jetpack/compose/navigation

To be specific, your Greeting composable will create a navigation request every single time it's rendered.

To work around, put navigation.navigate("greeting2") into a button callback. Currently the way it's written Greeting may get a chance to display because there is no delay before navigating to "greeting2".

The other way, if you want to navigate based on a data change:

if (dataNeededBeforeNavigating != null) {
  LaunchedEffect(Unit) {
    navigation.navigate("greeting2")
  }
}
mtf7101520 commented 2 years ago

邮件已经收到了,谢谢!