When using Jetpack Compose Navigation by Google, i...
# compose
a
When using Jetpack Compose Navigation by Google, if the routes are classes/data classes -> How do I check if the current
NavBackStackEntry
matches one of my Route definitions (the data classes that I have pushed into Jetpack Compose Navigation via
navController.navigate(route)
? For example: I navigated to
data class SomeRoute(val parameter: String)
and now I want to return
true
if the current
NavBackStackEntry
corresponds to
SomeRoute("hello")
👍 1
a
Wouldn’t this ommit the parameters of the route?
For example
SomeRoute("a")
and
SomeRoute("b")
would both return
true
if the entry corresponds to
SomeRoute
?
s
Yes it would. You can then after checking that it's this route, turn the backstack entry to the data class itself with toRoute(), and then compare the field yourself. Or even the entire object if that's what you want. Would that work for you?
a
So this is my usecase: Routes as described above, showing next to each other in a bottom navigation. Now I need to mark the currently selected bottom navigation item as selected depending on the current route. So that the item will get highlighted on the UI.
I would need to manually try to
hasRoute
with all possible routes, hardcoded since I need to provide the type I guess?
s
Is your bottom nav list a hardcoded list already or is that dynamic too?
a
its dynamic
s
You should be able to use the source of truth that drives which items should show on that bottom nav bar, and for each of those items, check if the current destination matches their route + their argument. Or something like that, I am not 100% sure of your details, but it feels quite possible.
a
controlled by the backend, but there is a fixed number of possibilities
I could store the selected item in a separate variable but this would add another source of truth. I would like to only use the navigation stack provided by the navigation library as my source of truth. For example if some outside force changes my current navigation item, I would like the correct tab to be highlighted still.
Seems kinda overly difficult for an actually pretty simple request atm
It should be possible to somehow check if the current destination of the NavController corresponds to a specific data class, at least that is what I expected. Doesn’t seem simple in the details.
s
Copy code
val backStackEntry = this
if (backStackEntry.hasRoute<MyDataClass>()) {
  val route = backStackEntry.toRoute<MyDataClass>()

  if (route == someExpectedInstanceOfMyDataClass) return true
  // or
  if (route.someField == "a") return true
}
return false
Something like this?
a
I would have to define an if for every possible Route and then inside of the if-check I would additionally have to check for the parameters. This is getting too large and complex - I am a bit annoyed that the Navigation Library is forcing me to do this to be frank, there are enough examples of other nav libs that are constructed in a way to make this case trivial, a one minute job. Anyways I have decided to wrap my navController in a TabsState which keeps track of the selected tabs. I am not happy about it but it will work.
👍 1
s
Yeah, it's all about trade-offs. Going with those libraries will have other disadvantages. If I knew the entire context around your problem I might've been able to suggest something cleaner, but from your explanation it looks like it shouldn't be too much work, especially considering you said the list of possible routes is not infinite but it defined.
a
It’s not infinite but very large. Having to provide a hand written check for every case also makes it easy to forget one case by accident without noticing. If I don’t write myself a code-generator for this case then the bugs will come very easy. That’s a lot of work for something that should be super easy. I guess my TabsState will do the job until something better can be done. At least it’s wrapped and hidden from the caller like that.
s
You can make your own function for this, which checks if the route matches the reified T type you pass in, and then does an equality check too after it does toRoute on it. This would make the check one line. Then after that's done, I don't understand what part would be too much work compared to how other libs would do it. You still need to know what to check against somewhere somehow. But as I said, I'm probably missing some context.
a
Could you give me an example of what you mean by the reified T type check? I tried something like that, it just never worked, I either got too many matches or none.
s
This https://kotlinlang.slack.com/archives/CJLTWPH7S/p1721212125766419?thread_ts=1721210495.829639&amp;cid=CJLTWPH7S but as a function itself. Something like
Copy code
fun main() {
  val navBackStackEntry: NavBackStackEntry = ...
  val didMatch = navBackStackEntry.matchesDestination(MyDestination("123"))
}

private inline fun <reified T : Any>  NavBackStackEntry.matchesDestination(expectedInstance: T): Boolean {
  if (!this.destination.hasRoute<T>()) {
    return false
  }
  val route = this.toRoute<T>()
  return route == expectedInstance
}
But I didn't run or write this in the IDE so not sure how it behaves, but it's what I had in mind at least. What did you write which was getting too many matches?
285 Views