Compose中Navigation抛出Illegal Argument错误的原因排查
Compose导航点击菜单崩溃问题解决
问题现象
在Compose中实现页面导航,导航逻辑定义在navigation.kt的Nav()函数中,通过give_route()匹配路由(匹配成功返回对应路由,否则返回page_not_found路由),路由字符串存于Address.kt密封类,页面Composable函数在Views/Pages.kt中。
运行时Feed页面正常显示,下拉菜单可展开,但点击菜单中任意按钮后应用崩溃,抛出如下错误:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.<company_name.<app_name>, PID: 20633 java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/New - Audio } cannot be found in the navigation graph NavGraph(0x0) startDestination={Destination(0x78c8aacb) route=Feed} ...[省略部分日志] I/Process: Sending signal. PID: 20633 SIG: 9
相关代码
navigation.kt
package com.<company_name.<app_name> import androidx.compose.runtime.Composable import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.<company_name.<app_name> // Class For function needed for Navigation @Composable fun Nav() { val navController = rememberNavController() NavHost(navController = navController, startDestination = Address.Feed.route) { composable(Address.Feed.route) { feed( Navi = {add -> navController.navigate(give_route(add))} ) } } } fun give_route(title: String): String { return when (title) { "Feed" -> Address.Feed.route "Question" -> Address.Question.route "Notice" -> Address.Notice.route "Status" -> Address.Status.route "DM" -> Address.DM.route "Chat" -> Address.Chat.route "Group_chat" -> Address.Group_chat.route "Notify" -> Address.Notify.route "Search" -> Address.Search.route "Profile" -> Address.Profile.route "Profile-Pvt" -> Address.Profile_Pvt.route "Profile-User" -> Address.Profile_User.route "Ratting" -> Address.Ratting.route "New - Text" -> Address.New_Text.route "New - Image" -> Address.New_Image.route "New - Video" -> Address.New_Video.route "New - Audio" -> Address.New_Audio.route "New - Other" -> Address.New_File.route else -> Address.page_not_found.route } }
Address.kt
package com.<company_name.<app_name> sealed class Address(val route: String) { object Feed : Address("Feed") object Question : Address("Question") object Notice : Address("Notice") object Status : Address("Status") object DM : Address("DM") object Chat : Address("Chat") object Group_chat : Address("Group_chat") object Notify : Address("Notify") object Search : Address("Search") object Profile : Address("Profile") object Profile_Pvt : Address("Profile-Pvt") object Profile_User : Address("Profile-User") object Ratting : Address("Ratting") object New_Text : Address("New - Text") object New_Image : Address("New - Image") object New_Video : Address("New - Video") object New_Audio : Address("New - Audio") object New_File : Address("New - File") object page_not_found : Address("Page not found") }
MainActivity.kt
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { AppTheme { // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { Nav() } } } } }
Pages.kt
package com.<company_name.<app_name> import androidx.compose.foundation.layout.Row import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.* import androidx.compose.material3.* import androidx.compose.runtime.* // PAGE VIEWS // Feed View @Composable fun feed(Navi: (String) -> Unit) { var newPost by remember { mutableStateOf(false) } // TODO - y Row() { FilledTonalIconButton( onClick = { newPost = true }, enabled = true ) { Icon( Icons.Rounded.Add, "Button for creating a new post. " + "Opens the Menu to selct the type for your new post" ) } DropdownMenu( expanded = newPost, onDismissRequest = { newPost = false } ) { DropdownMenuItem( text = { Text("Text") }, onClick = { Navi("New - Text") }, enabled = true, leadingIcon = { Icon(Icons.Rounded.ViewHeadline, "To Post Text" ) } ) DropdownMenuItem( text = { Text("Image") }, onClick = { Navi("New - Image") }, enabled = true, leadingIcon = { Icon(Icons.Rounded.Wallpaper, "To Post Image" ) } ) DropdownMenuItem(text = { Text("Video") }, onClick = { Navi("New - Video") }, enabled = true, leadingIcon = { Icon(Icons.Rounded.Slideshow, "To Post Video" ) } ) DropdownMenuItem(text = { Text("Audio") }, onClick = { Navi("New - Audio") }, enabled = true, leadingIcon = { Icon(Icons.Rounded.SpatialAudioOff, "To Post Audio" ) } ) DropdownMenuItem(text = { Text("Other") }, onClick = { Navi("New - Other") }, enabled = true, leadingIcon = { Icon(Icons.Rounded.PostAdd, "To open custom file window for posting user file" ) } ) } } } @Composable fun New_Text() { Text("a") } @Composable fun New_Image() { Text("b") } @Composable fun New_Video() { Text("c") } @Composable fun New_Audio() { Text("d") } @Composable fun New_File() { Text("e") }
问题原因与解决方案
原因
崩溃的核心原因是导航图(NavHost)中只注册了Feed页面的路由,其他页面的路由没有添加到导航图中。当调用navController.navigate()跳转到其他路由时,Navigation组件找不到对应的目的地,因此抛出IllegalArgumentException。
解决方案
在Nav()函数的NavHost中,为所有需要导航到的页面添加对应的composable节点。
修改后的navigation.kt代码如下:
package com.<company_name.<app_name> import androidx.compose.runtime.Composable import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.<company_name.<app_name> @Composable fun Nav() { val navController = rememberNavController() NavHost(navController = navController, startDestination = Address.Feed.route) { // Feed页面 composable(Address.Feed.route) { feed(Navi = { add -> navController.navigate(give_route(add)) }) } // 新增所有需要导航的页面节点 composable(Address.New_Text.route) { New_Text() } composable(Address.New_Image.route) { New_Image() } composable(Address.New_Video.route) { New_Video() } composable(Address.New_Audio.route) { New_Audio() } composable(Address.New_File.route) { New_File() } // 其他页面同理,需要导航的都要添加对应的composable composable(Address.Question.route) { // 这里替换为对应的Question页面Composable } composable(Address.Notice.route) { // 这里替换为对应的Notice页面Composable } // ... 其他路由节点依次添加 composable(Address.page_not_found.route) { // 可以添加404页面的Composable } } } fun give_route(title: String): String { return when (title) { "Feed" -> Address.Feed.route "Question" -> Address.Question.route "Notice" -> Address.Notice.route "Status" -> Address.Status.route "DM" -> Address.DM.route "Chat" -> Address.Chat.route "Group_chat" -> Address.Group_chat.route "Notify" -> Address.Notify.route "Search" -> Address.Search.route "Profile" -> Address.Profile.route "Profile-Pvt" -> Address.Profile_Pvt.route "Profile-User" -> Address.Profile_User.route "Ratting" -> Address.Ratting.route "New - Text" -> Address.New_Text.route "New - Image" -> Address.New_Image.route "New - Video" -> Address.New_Video.route "New - Audio" -> Address.New_Audio.route "New - Other" -> Address.New_File.route else -> Address.page_not_found.route } }
这样修改后,所有需要导航的路由都在NavHost中注册了对应的目的地,点击菜单按钮时就能正常跳转,不会再出现崩溃。
内容的提问来源于stack exchange,提问作者user20603322
相关产品推荐
相关产品推荐

