I am creating an explicit deeplink to a fragment in my app (Navigation component). This is how I am currently doing it:
val args = bundleOf(
"roomId" to roomId,
"receiver" to receiver
)
return NavDeepLinkBuilder(context)
.setGraph(R.navigation.nav_graph_home)
.addDestination(R.id.navigation_chat_private)
.setArguments(args)
.createPendingIntent()
The arguments are defined in the nav_graph like this:
<argument android:name="roomId" app:argType="string" />
<argument android:name="receiver" app:argType="integer" />
This works without issue. But I can't help but wonder if there is a way to avoid hardcoding the parameter names twice. I feel like there HAS to be a better way. Something along the lines of:
val chatArgs = NavigationChatPrivateArgs(roomId,receiver)
return NavDeepLinkBuilder(context)
.setGraph(R.navigation.nav_graph_home)
.addDestination(R.id.navigation_chat_private)
.setArguments(chatArgs.toBundle())
.createPendingIntent()
But there is no such constructor in the generated safeArgs class. I also tried calling the empty constructor and then setting the values, but the args are vals, so cannot be reassigned. Is anybody aware of an elegant way to do this?
When you use the Safe Args plugin to generate Kotlin code via the
androidx.navigation.safeargs.kotlinplugin, each Args class is given a constructor that uses arguments for required arguments and default arguments for parameters that have adefaultValueor that arenullable.This lets you generate exactly the code you've posted:
However, when you generate Java code via the
androidx.navigation.safeargsplugin, default arguments are not available. Therefore the Java code uses a builder pattern - you construct aNavigationChatPrivageArgs.Builderinstance, which takes required arguments as constructor parameters for theBuilderclass and optional parameters as additional setters available on theBuilderand then callbuild()on theBuilderto construct the class.So in all cases, yes, you can directly create your Args class exactly for use in cases like this or in tests.