2

Since the navigation files are in app module, feature modules won't have access to the Args file. Is there any workaround for that?

example: if I have a fragment which accepts email and password like so

<fragment
        android:id="@+id/navigation_sample"
        android:name="SampleFragment">
        <argument
            android:name="email"
            app:argType="string" />
        <argument
            android:name="password"
            app:argType="string" />
    </fragment>

I would have a SampleFragmentArgs generated which could be used to navigate

findnavController.navigate(R.id.navigation_sample, SampleFragmentArgs(email, password).toBundle)

But I can use this only from app module not in a feature module

2 Answers 2

5

It depends on what you call a "feature module", however I'm assuming that should be android library.

This is the setup that works:

  1. Say your android library is called "mylibrary"
  2. Your "app" module naturally should have the above as dependency
  3. Your "mylibrary" should have apply plugin: "androidx.navigation.safeargs.kotlin" and corresponding setting in classpath of library top level build.gradle
  4. Let's declare navigation graph inside library (say, mylibrary_graph.xml with id myLibraryGraph), just like you'd do in "app" module - and let's assume it has your "SampleFragment" as starting point, with all those arguments listed.
  5. Let's say your "app" module has some navigation graph and let's include "mylibrary_graph.xml" as nested there (<include app:graph="@navigation/mylibrary_graph" />)
  6. Let's say your "app" module nav graph in question has some fragment that needs to jump to your "SampleFragment" inside your android library. We'll declare it like this (pseudo code) :
    <fragment
        android:id="@+id/HelloWorldFragment"
        android:name="..."
        android:label="..."
        tools:layout="...">

        <action
            android:id="@+id/jumpToSampleFragment"
            app:destination="@+id/myLibraryGraph">

          <argument
              android:name="email"
              app:argType="string" />
          <argument
              android:name="password"
              app:argType="string" />
        </action>
    </fragment>
  1. Finally, you can then do this inside your HelloWorldFragment: findNavController().navigate(HelloWorldFragmentDirections.jumpToSampleFragment("[email protected]", "nimda"))

As one can see it works but there is somewhat minor inconvenience of declaring arguments in 2 places.

Sign up to request clarification or add additional context in comments.

3 Comments

Putting navigation file in the library would have the following problem. You are inside mylibraryA and on click of a button you want to navigate to libraryB. How would you do it? Since libraryA doesn't know about libraryB nor app.
In exactly the same way. Having androidlib1 and androidlib2 with need to navigate from one to another, you are adding dependency and you are navigating exactly the same way as you would do from app to androidlib1.
I don't understand. I think my answer addresses your original question - does it? If so, please accept/upvote etc.
0
  • Create the extension function for the NavController, or, in java, you could create a static helper class with method perhaps.
fun NavController.navigate(directions:NavDirections, @NavigationRes graphId : Int) {
            val currentGraph = graph
            val desiredAction = currentGraph.getAction(directions.actionId)
            val destId = if(desiredAction == null) {
                val graph = navInflater.inflate(graphId)
                currentGraph.addAll(graph)
                graph.getAction(directions.actionId)!!.destinationId
            } else {
                desiredAction.destinationId
            }
            navigate(destId, directions.arguments)
        }
  • Have a main navigation graph: navigation_main.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/navigation_main"
  app:startDestination="@id/fragment">

  <fragment
    android:id="@+id/fragment"
    android:name="my.package.MyFragment"/>
</navigation>

  • Create a library navigation graph (in your library): navigation_library.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/navigation_library"
  app:startDestination="@id/another_fragment">

  <fragment
    android:id="@+id/another_fragment"
    android:name="my.package.AnotherFragment">
        <argument
            android:name="defaultValue"
            android:defaultValue="@null"
            app:argType="java.time.LocalDate"
            app:nullable="true" />
  </fragment>
  <action
        android:id="@+id/action_global_another_fragment"
        app:destination="@id/another_fragment" />
</navigation>
  • Add this code inside e.g. a button click listener in MyFragment
val directions = AnotherFragmentDirections.actionGlobalAnotherFragment(LocalDate.now())
            parent.findNavController().navigate(directions, R.navigation.navigation_library)

If you need to navigate to another library from this library, you'd simply create a graph in that library and navigate to the destination inside it using the same trick.

I have this situation since I have a navigation graph in my app. The app depends on a feature module, and that feature module makes use of what I'd call a core module of useful fragments to pick date and time.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.