Jetpack Compose ナビゲーション - startDestination に引数を渡す 質問する

Jetpack Compose ナビゲーション - startDestination に引数を渡す 質問する

私が構築しているアプリは、ルートを使用した Compose ナビゲーションを使用しています。課題は、開始先が動的であることです。

以下に最小限の例を示します。

class MainActivity : ComponentActivity()
{
    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)

        setContent {
            val navController = rememberNavController()

            NavHost(
                navController = navController,
                startDestination = "dynamic/1", // doesn't work
                // startDestination = "static", // workaround
            ) {
                composable(
                    route = "dynamic/{$ARG_ID}",
                    arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType }),
                ) {
                    val id = it.arguments?.getString(ARG_ID)
                    Text("dynamic route, received argument: $id!")
                }
                // part of the workaround
                // composable(
                //  route = "static",
                // ) {
                //  LaunchedEffect(this) {
                //      navController.navigate("dynamic/1")
                //  }
                // }
            }
        }
    }

    companion object
    {
        const val ARG_ID = "id"
    }
}

アプリがクラッシュする

java.lang.IllegalArgumentException: navigation destination route/1 is not a direct child of this NavGraph

この問題は、「動的」ルートが開始先として使用されている場合にのみ発生します。これは、 を使用して確認できますstartDestination = "static"

「静的」ルートの回避策は機能しますが、コードが難読化され、バックスタックに追加のエントリも作成されるため、それを使用しないソリューションを探しています。

->完全なコードサンプル問題を再現する

関連するSOの質問

編集:

元のサンプルには「静的」コンポーザブルが含まれていなかったことを強調しておきます。「静的」コンポーザブルを追加したのは、動作を確認しstartDestination、「動的」コンポーザブルに移動できることを証明するためだけです。

アップデート:

に切り替えてもオプション引数のクエリパラメータ構文デフォルト値を指定し、引数なしで開始先を設定しても機能しません。

次のバリエーション

NavHost(
    navController = navController,
    startDestination = "dynamic",
) {
    composable(
        route = "dynamic?$ARG_ID={$ARG_ID}",
        arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType; defaultValue = "1" }),
    ) {
        val id = it.arguments?.getString(ARG_ID)
        Text("dynamic route, received argument: $id!")
    }
}

例外につながる

java.lang.IllegalArgumentException: navigation destination dynamic is not a direct child of this NavGraph

ベストアンサー1

全ての功績はイアン・ハニバルケ、コメントで解決策を説明してくれました。ここでは、私のコードサンプルの動作バージョンを紹介します。

私にとっての大きな洞察は次の通りです。

startDestinationrouteパターンマッチングの意味で構成可能要素と一致してはならないが、正確に同じ文字列でなければならない

つまり、引数は を介し​​てstartDestination直接設定することはできず、引数の を介して設定する必要がありますdefaultValue

実際のサンプルは次のとおりです。

class MainActivity : ComponentActivity()
{
    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)

        setContent {
            val navController = rememberNavController()

            NavHost(
                navController = navController,
                // 1st change: Set startDestination to the exact string of route
                startDestination = "dynamic/{$ARG_ID}", // NOT "dynamic/1", provide arguments via defaultValue
            ) {
                composable(
                    route = "dynamic/{$ARG_ID}",
                    // 2nd change: Set startDestination argument via defaultValue
                    arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType; defaultValue = "1" }),
                ) {
                    val id = it.arguments?.getString(ARG_ID)
                    Text("dynamic route, received argument: $id!")
                }
            }
        }
    }

    companion object
    {
        const val ARG_ID = "id"
    }
}

このアプローチは、クエリ パラメータの形式で提供される引数でも同様に機能します。

正直に言うと、開始ルートによって が何でなければならないかが決まるようになったため、これは小さな制限だと考えています。defaultValue別の を設定するdefaultValueか、まったく を設定しない方がよい場合もあります。しかし、ほとんどの場合、これが最もエレガントな解決策になるはずです。

おすすめ記事