13

I have a NavGraph that looks like this:

@Composable
fun NavGraph (
    navController: NavHostController
) {
    NavHost(
        navController = navController,
        startDestination = "Products"
    ) {
        composable(
            route = "Products"
        ) {
            ProductsScreen(
                navController = navController
            )
        }
        composable(
            route = "Product Details",
            arguments = listOf(
                navArgument("product") {
                    type = NavType.SerializableType(Product::class.java)
                }
            )
        ) {
            val product = navController.previousBackStackEntry?.arguments?.getSerializable("product") as Product
            ProductDetailsScreen(
                navController = navController,
                product = product
            )
        }
    }
}

Inside the ProductDetailsScreen, I want on product click to navigate further to details screen passing a Product object:

LazyColumn {
    items(
        items = products
    ) { product ->
        ProductCard(
            product = product,
            onProductClick = {
                navController.currentBackStackEntry?.arguments?.putSerializable("product", product)
                navController.navigate("Product Details")
            }
        )
    }
}

The products are perfectly displayed but when I click on a product, the app crashes with this error:

java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/Product Details } cannot be found in the navigation graph NavGraph(0x0) startDestination={Destination(0xb543811) route=Products}

Can anyone help?

P.S. I also followed this answer but no luck :(

Joan P.
  • 2,368
  • 6
  • 30
  • 63

4 Answers4

12

Make sure you have all the argument names and route names correctly setup and avoid spaces, use underscores when you want to break words

My Mistake

The argument name in the route definition and while supplying in the navArgument block should be same

composable(
                        "pokemon_detail_screen/{dominantColor}/{pokemonName}", //Notice over here
                        arguments = listOf(
                            navArgument("dominantColor") {
                                type = NavType.IntType
                            },
                            navArgument("pokemon_name") { // Notice over here
                                type = NavType.StringType
                            }
                        )
                    )

Took me quite some time to figure it out so be very careful

gtxtreme
  • 1,830
  • 1
  • 13
  • 25
5

I had this error when i was using json as string to pass class to my navigation here is how i implemented :

 composable(
            "details/{MyObject}",
            arguments = listOf(navArgument("MyObject") {
                type = NavType.StringType
            })
        ) {
            it.arguments?.getString("MyObject")?.let { jsonString ->
                var issue = MyObject()
                if (!jsonString.isNullOrEmpty())
                    issue = jsonString.fromJson(MyObject::class.java)
                DetailsView(navController = navController, detailsViewModel, myObject = MyObject)
            }
        }

And how i call it :

val gson = Gson()
var myObjectString = gson.toJson(myObject, MyObject::class.java)
navController.navigate("details/$myObjectString")

And here sometime i was getting the Navigation destination that matches request NavDeepLinkRequest cannot be found in the navigation graph NavGraph error and sometimes i didn't got it. it was depending on the object i was clicking.

I think it's because some of my data was not well formed when i got the answer from the api meaning i might have some unwanted characters when i was transforming it to json. To avoid that i encoded my json in utf8 like so :

var encode = URLEncoder.encode(myObjectString,StandardCharsets.UTF_8.toString())
navController.navigate("details/$encode")

Then i didn't got the navigation error again, i hope that could help people that are trying to use jetpack compose navigation with json to send object

XCarb
  • 735
  • 10
  • 31
0

It is my sample

@ExperimentalPagerApi
@Composable
fun WallNavigation(nameFolder: String, paths: List<String>) {
   val navController = rememberNavController()
   val model: ImageViewModel = viewModel()
   model.setFolder(nameFolder)
   model.setFileNames(paths)

   NavHost(navController = navController, startDestination = Screen.MainScreen.route) {
    composable(Screen.MainScreen.route) {
        MainScreen(navController = navController, model)
    }

    composable(route = Screen.GalleryScreen.route + "/{position}", arguments = listOf(navArgument(name = "position") {
        type = NavType.IntType
        defaultValue = -1
        nullable = false
    })) { entity ->
        GalleryScreen(navController = navController, position = entity.arguments?.getInt("position") ?: -1, imageViewModel = model)
    }

    composable(route = Screen.CropScreen.route) {
        CropScreen(navController = navController, imageViewModel = model)
    }
  }
} 

sealed class Screen(val route : String) {
    object MainScreen : Screen("main_screen")
    object GalleryScreen : Screen("gallery_screen")
    object CropScreen : Screen("crop_screen")

    fun withArgs(vararg args: String):String {
       return buildString {
          append(route)
          args.forEach { arg ->
              append("/$arg")
          }
        }
     }
}
Alexander
  • 511
  • 4
  • 14
  • Let me try to understand and get back to you. Thanks – Joan P. Jan 12 '22 at 13:12
  • Unfortunately, it doesn't work for me, as I need to send an entire object of type `Product` from one screen to another. – Joan P. Jan 12 '22 at 13:27
  • 1
    @JoanP. No problem, just use ViewModel. You can sen id of a product. Whole the product you can get from ViewModel. I do the same action in my sample. – Alexander Jan 12 '22 at 13:32
  • @JoanP. The equal problem https://stackoverflow.com/questions/67121433/how-to-pass-object-in-navigation-in-jetpack-compose – Alexander Jan 12 '22 at 13:35
  • Are you also converting it to JSON string too? Voted up for your effort. – Joan P. Jan 12 '22 at 14:18
  • @JoanP. No. I have a list in ViewModel. Also, you can use a single ViewModel for "Products" and "Product Detail" screens. I guess you a place where you saving the list of products. Add a method "fun getDetail(id: String): Product" in the place – Alexander Jan 12 '22 at 14:41
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/240998/discussion-between-alexander-and-joan-p). – Alexander Jan 12 '22 at 14:44
  • No, I'm not using `fun getDetail(id: String): Product`. Why? Because don't need that. All data that I need is inside the object that I want to pass to the other screen. I don't need any other request. – Joan P. Jan 12 '22 at 14:46
  • Sure, You don't need another request. You have a response. Why do you use it a second time? I guess you have a repository for the response. – Alexander Jan 12 '22 at 15:00
  • I think this guy over here, just answered my new [question](https://stackoverflow.com/questions/70683394/why-can-we-not-pass-a-serializable-object-to-navarguments), and it makes sense. Thanks for you time and effort. – Joan P. Jan 12 '22 at 15:04
0

This answer explains really good how to pass a parcelable argument with compose navigation.

The error message you describe above that the navigation destination that matches request NavDeepLinkRequest cannot be found in the navigation graph NavGraph can also appear when you want to hand over an optional argument and forget to make it nullable.

  arguments: List<NamedNavArgument> = listOf(
            navArgument("product") {
                type = Product.NavigationType //check out the linked answer to know how to write the Product.NavigationType
                nullable = true
            }
        )
jendress
  • 109
  • 1
  • 5
  • This is my situation. I set the deeplink for that Composable but forget to make an argument to be nullable. After setting it, everything works. – FunnySaltyFish May 25 '23 at 14:27