Multi-module Navigation with Architecture Components

前端 未结 3 1518
醉酒成梦
醉酒成梦 2021-01-30 21:48

So I have this structure for my modules in my current app.

I haven\'t found any official documentation on multi-module navigation yet but I found this article r

相关标签:
3条回答
  • 2021-01-30 22:24

    It is possible to remove all Gradle inter-feature dependencies when you declare each feature nav graph ID explicitly in the base feature. I am not 100% satisfied with this solution since these IDs create "hidden" inter-feature dependencies but otherwise it works fine.

    Here are the key parts of this setup:

    :app

    build.gradle

    dependencies {
        implementation project(':features:feature-base')
        implementation project(':features:feature-one')
        implementation project(':features:feature-two')
    }
    

    :features:feature-base

    build.gradle

    dependencies {
        application project(':app')
        feature project(':features:feature-one')
        feature project(':features:feature-two')
    }
    

    navigation/feature_base_nav_graph.xml

    <navigation ...>
        <include app:graph="@navigation/feature_one_nav_graph" />
        <include app:graph="@navigation/feature_two_nav_graph" />
    </navigation>
    

    values/feature_base_ids.xml

    <resources>
        <item name="feature_one_nav_graph" type="id" />
        <item name="feature_two_nav_graph" type="id" />
    </resources>
    

    :features:feature-one

    build.gradle

    dependencies {
        implementation project(':features:feature-base')
    }
    

    navigation/feature_one_nav_graph.xml

    <navigation
        android:id="@id/feature_one_nav_graph"
        ...>
    
        <fragment
            android:id="@+id/oneFragment"
            ...>
            <action
                android:id="@+id/navigateToFeatureTwo"
                app:destination="@id/feature_two_nav_graph"
                ... />
        </fragment>
    
    </navigation>
    

    navigate

    findNavController().navigate(R.id.navigateToFeatureTwo)
    

    :features:feature-two

    build.gradle

    dependencies {
        implementation project(':features:feature-base')
    }
    

    navigation/feature_two_nav_graph.xml

    <navigation
        android:id="@id/feature_two_nav_graph"
        ...>
    
        <fragment
            android:id="@+id/twoFragment"
            ...>
            <action
                android:id="@+id/navigateToFeatureOne"
                app:destination="@id/feature_one_nav_graph"
                ... />
        </fragment>
    
    </navigation>
    

    navigate

    findNavController().navigate(R.id.navigateToFeatureOne)
    
    0 讨论(0)
  • 2021-01-30 22:41

    One of the approaches that might be useful is to create a completely new independent module (e.g ":navigation" module) and move all navigation.xml files from all other modules to it. Then we depend on that new (":navigation") module in all other modules where navigation related stuff is needed, and we will be able to access its R.navigation or generated argument classes, etc.

    Since the new (":navigation") module doesn't know about anything else in the project IDE will mark red any fragment, activity and other classes we use in navigation.xml files, that are defined outside in other modules but as long as we use full class names (com.exampel.MyFragment) it will compile and work.

    <?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"
        android:id="@+id/nav_graph_id"
        app:startDestination="@id/some_navigation_id">
    
        <fragment
            android:id="@+id/some_navigation_id"
            android:name="com.exampel.MyFragment".../>
            // com.exampel.MyFragment will be marked red since IDE can't link it
            // to the existing class because it is in the other module
    

    This creates "hidden" dependency to all classes we want to navigate to in a way that we need to know class names and potentially arguments, and we have to maintain it manually but it allow us to easily separate navigation in independent module.

    0 讨论(0)
  • 2021-01-30 22:42

    This is already a year-long but the library now can support this exact use-case! As of 2.1.0-alpha03, we can navigation through deep link URIs.

    Instead of adding the features as implementation details to each other, we can leave them unaware between themselves and use deep link navigation.

    Feature 1 - Detail - build.gradle

    dependencies {
        implementation project(':base')
    }
    

    Same with Feature 2 - Detail. No need for it to know the other modules.

    To have inter-module navigation, we have to first define the deep link for navigating through that destination via a deepLink tag.

    Feature 1 - Detail - Navigation Graph

    <navigation ...
        android:id="@+id/graph_feature_1_detail_id">
        <fragment ...
            android:id="@+id/nav_feature_1_detail">
            <deepLink app:uri="myApp://feature1detail"/>
    
        </fragment>
    </navigation>
    

    Feature 2 - Detail - Navigation Graph

    <navigation ...
        android:id="@+id/graph_feature_2_detail_id">
        <fragment ...
            android:id="@+id/nav_feature_2_detail">
            <deepLink app:uri="myApp://feature2detail"/>
    
        </fragment>
    </navigation>
    

    Now that we have deep links with URIs set, we can directly use this in a NavController

    So in the fragment in Feature 1 - Detail, maybe on a button click? Anywhere where you have to perform navigation

    class Feature1DetailFragment {
       fun onViewCreated(...) {
           ...
           view.setOnClickListener {
               val uri = Uri.parse("myApp://feature2detail")
               findNavController().navigate(uri)
           }
       }
    }
    
    

    And in Feature 2 - Detail,

    class Feature2DetailFragment {
       fun onViewCreated(...) {
           ...
           view.setOnClickListener {
               val uri = Uri.parse("myApp://feature1detail")
               findNavController().navigate(uri)
           }
       }
    }
    
    

    And voila! Inter-module navigation.

    At the time of writing, the latest stable release is 2.1.0-rc01.

    Although I haven't tried this out on more complex projects, I love this library and I'm hoping to see this library mature more!

    I created a Medium article about this. You can take a look at it. Cheers!

    0 讨论(0)
提交回复
热议问题