0

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?

ShahiM
  • 3,179
  • 1
  • 33
  • 58
  • Every args definitely allows you to construct it in full completely manually with exactly the expected code you've included if you've generated your Safe Args in Kotlin (using the `androidx.navigation.safeargs.kotlin` plugin). Are you generating Kotlin Safe Args code or generating Java Safe Args code (using the `androidx.navigation.safeargs` plugin)? – ianhanniballake Mar 16 '23 at 16:32
  • Yes. That was it. I switched to the kotlin safeargs plugin and it worked. Can you post it as an answer so I can accept it? – ShahiM Mar 17 '23 at 05:38

1 Answers1

1

When you use the Safe Args plugin to generate Kotlin code via the androidx.navigation.safeargs.kotlin plugin, each Args class is given a constructor that uses arguments for required arguments and default arguments for parameters that have a defaultValue or that are nullable.

This lets you generate exactly the code you've posted:

val chatArgs = NavigationChatPrivateArgs(roomId,receiver)
val bundle = chatArgs.toBundle()

However, when you generate Java code via the androidx.navigation.safeargs plugin, default arguments are not available. Therefore the Java code uses a builder pattern - you construct a NavigationChatPrivageArgs.Builder instance, which takes required arguments as constructor parameters for the Builder class and optional parameters as additional setters available on the Builder and then call build() on the Builder to construct the class.

// Assuming both parameters are required
val chatArgs = NavigationChatPrivateArgs.Builder(roomId,receiver).build()
val bundle = chatArgs.toBundle()

So in all cases, yes, you can directly create your Args class exactly for use in cases like this or in tests.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443