Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to navigate from nested Fragment to parent fragment using Jetpack Navigation?

I have main navigation: SplashFragment -> RegistrationFragment -> RootFragment

<fragment
    android:id="@+id/splashFragment"
    android:name="com.low6.low6.features.splash.SplashFragment"
    android:label="Splash"
    tools:layout="@layout/fragment_splash" >
    <action
        android:id="@+id/action_next"
        app:clearTask="true"
        app:destination="@id/registrationFragment" />
</fragment>

<fragment
    android:id="@+id/registrationFragment"
    android:name="com.low6.low6.features.registration.RegistrationFragment"
    android:label="Register">
    <action
        android:id="@+id/action_next"
        app:clearTask="true"
        app:destination="@id/rootFragment" />
</fragment>

<fragment
    android:id="@+id/rootFragment"
    android:name="com.low6.low6.core.RootFragment"
    android:label="@string/home"
    tools:layout="@layout/fragment_root" />

And I have nested registration navigation: RegistrationPersonalFragment -> RegistrationContactFragment -> RegistrationSecurityFragment

<fragment
    android:id="@+id/registrationPersonalFragment"
    android:name="com.low6.low6.features.registration.RegistrationPersonalFragment"
    android:label="Register">

    <action
        android:id="@+id/action_next"
        app:destination="@+id/registrationContactFragment" />
</fragment>

<fragment
    android:id="@+id/registrationContactFragment"
    android:name="com.low6.low6.features.registration.RegistrationContactFragment"
    android:label="Register">

    <action
        android:id="@+id/action_next"
        app:destination="@+id/registrationSecurityFragment" />
</fragment>

<fragment
    android:id="@+id/registrationSecurityFragment"
    android:name="com.low6.low6.features.registration.RegistrationSecurityFragment"
    android:label="Register">

    <action
        android:id="@+id/action_next"
        app:destination="@+id/rootFragment" />
</fragment>

How to redirect from the last nested RegistrationSecurityFragment to RootFragment using Jetpack Navigation component?

Currently

<action
    android:id="@+id/action_next"
    app:destination="@+id/rootFragment" />

And

   navigateTo(R.id.action_next)

Gives me

    java.lang.IllegalArgumentException: navigation destination com.xxx:id/rootFragment referenced from action com.xxx:id/action_next is unknown to this NavController
    at androidx.navigation.NavController.navigate(NavController.java:691)
    at androidx.navigation.NavController.navigate(NavController.java:648)
    at androidx.navigation.NavController.navigate(NavController.java:634)
    at com.xxx.core.BaseFragment.navigateTo(BaseFragment.kt:73)
    at com.xxx.core.BaseFragment.navigateTo$default(BaseFragment.kt:66)
    at com.xxx.features.registration.RegistrationSecurityFragment$epoxyController$1$$special$$inlined$button$lambda$1.onClick(RegistrationSecurityFragment.kt:106)
    at android.view.View.performClick(View.java:6597)
    at android.view.View.performClickInternal(View.java:6574)
    at android.view.View.access$3100(View.java:778)
    at android.view.View$PerformClick.run(View.java:25885)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
like image 543
qbait Avatar asked Oct 10 '18 08:10

qbait


People also ask

What is nested fragment?

Fragments represent a behavior or portion of UI in an Activity. Fragments are mostly used in tablets to divide screen and utilize screen space in efficient way. With Android 4.2 nested fragments are introduced, with which now you can embed fragments inside fragments.


2 Answers

When you have nested NavControllers, findNavController() return only last. To get previous navControllers, you can traverse up using parentFragment property.

Extensions with this approach:

// find all nav controllers from closest to farest
fun Fragment.findAllNavControllers(): List<NavController> {
    val navControllers = mutableListOf<NavController>()
    var parent = parentFragment
    while (parent != null) {
        if (parent is NavHostFragment) {
            navControllers.add(parent.navController)
        }
        parent = parent.parentFragment
    }
    return navControllers
}

// find one nav controller by fragment id
fun Fragment.findNavControllerById(@IdRes id: Int): NavController {
    var parent = parentFragment
    while (parent != null) {
        if (parent is NavHostFragment && parent.id == id) {
            return parent.navController
        }
        parent = parent.parentFragment
    }
    throw RuntimeException("NavController with specified id not found")
}

And usage:

findAllNavControllers()[2]
findNavControllerById(R.id.navHostFragment)
like image 62
Pavel Shorokhov Avatar answered Oct 22 '22 13:10

Pavel Shorokhov


If you have more than one navigation graph, please make sure you're using the right navigation controller. Using Navigation.findNavController(view) in some cases you might need to get your root view to get the root's navigation. Hope, this'll help.

like image 41
Vladimir Gladun Avatar answered Oct 22 '22 13:10

Vladimir Gladun