私が構築しているアプリは、ルートを使用した 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 に渡す- 回答は Compose ナビゲーションには適用できないようです。
- Jetpack Compose のネストされたナビゲーション グラフに引数を渡す- 回答なし。
- ナビゲーションの作成 - ナビゲーションの目的地...はこの NavGraph の直接の子ではありません- 承認された回答では問題は解決されません。
編集:
元のサンプルには「静的」コンポーザブルが含まれていなかったことを強調しておきます。「静的」コンポーザブルを追加したのは、動作を確認し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
全ての功績はイアン・ハニバルケ、コメントで解決策を説明してくれました。ここでは、私のコードサンプルの動作バージョンを紹介します。
私にとっての大きな洞察は次の通りです。
startDestination
route
パターンマッチングの意味で構成可能要素と一致してはならないが、正確に同じ文字列でなければならない。
つまり、引数は を介して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
か、まったく を設定しない方がよい場合もあります。しかし、ほとんどの場合、これが最もエレガントな解決策になるはずです。