21

I am making app, which supports different device orientations. Navigation is carried out by Android Jetpack's Navigation. App main screen for landscape orientation is present below. It is list wrapper fragment (it is NavHostFragment, it is added to activity's layout in fragment tag), wrapper includes list fragment (fragment) and details fragment (FrameLayout). Portrait orientation is similar (wrapper and list in it, details is accessible throw navigation).

App main screen

My problem is after I change device orientation I get exception

java.lang.IllegalStateException: no current navigation node

First version of my layout with mocked data worked fine, the error appears after I add ROOM to my app, new order and update order fragments. It is a pity, I cannot localize source of error more exact.

List wrapper code

class OrderListWrapperFragment : RxFragment() {

    private val disposable = CompositeDisposable()

    var selectedOrderId: Long = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val bundle = savedInstanceState ?: arguments
        bundle?.let {
            selectedOrderId = it.getLong(EXTRA_ORDER_ID)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater.inflate(R.layout.orders__list_wrapper, container, false)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        initializeToolbar(toolbar, getString(R.string.orders_title), false)

        newOrderButton
            .clicks()
            .subscribe {
                findNavController()
                    .navigate(R.id.action_orderListWrapperFragment_to_orderNewFragment)
            }
            .addTo(disposable)

        childFragmentManager.registerFragmentLifecycleCallbacks(callback, false)
    }

    override fun onDestroyView() {
        super.onDestroyView()

        childFragmentManager.unregisterFragmentLifecycleCallbacks(callback)

        disposable.clear()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)

        outState.putLong(EXTRA_ORDER_ID, selectedOrderId)
    }

    private val callback = object : FragmentManager.FragmentLifecycleCallbacks() {

        private val disposable = CompositeDisposable()

        override fun onFragmentResumed(fm: FragmentManager, fragment: Fragment) {
            super.onFragmentResumed(fm, fragment)

            if (fragment is OrderListFragment) {
                fragment
                    .selectedItemIdChanges
                    .subscribeBy(onNext = {
                        selectedOrderId = it
                        if (orderDetailsContainer != null) {
                            childFragmentManager.commit {
                                replace(
                                    R.id.orderDetailsContainer,
                                    OrderDetailsFragment.newInstance(it)
                                )
                            }
                        } else {
                            findNavController()
                                .navigate(
                                    R.id.action_orderListWrapperFragment_to_orderDetailsFragment,
                                    bundleOf(EXTRA_ORDER_ID to it)
                                )
                            selectedOrderId = 0
                        }
                    },
                        onError = {
                            Log.d("detailView", it.toString())
                        })
                    .addTo(disposable)

                val orderId = selectedOrderId
                if (orderId != 0L) {
                    if (orderDetailsContainer != null) {
                        childFragmentManager.commit {
                            replace(
                                R.id.orderDetailsContainer,
                                OrderDetailsFragment.newInstance(orderId)
                            )
                        }
                    } else {
                        findNavController()
                            .navigate(//exception throws here
                                R.id.action_orderListWrapperFragment_to_orderDetailsFragment,
                                bundleOf(EXTRA_ORDER_ID to orderId)
                            )
                        selectedOrderId = 0
                    }
                }
            }
        }

        override fun onFragmentPaused(fm: FragmentManager, fragment: Fragment) {
            super.onFragmentPaused(fm, fragment)

            if (fragment is OrderListFragment) {
                disposable.clear()
            }
        }
    }

    companion object {
        private const val EXTRA_ORDER_ID = "EXTRA_ORDER_ID"
    }
}

My navigation graph

<?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_graph"
    app:startDestination="@id/orderListWrapperFragment">

    <fragment
        android:id="@+id/orderListWrapperFragment"
        android:name="com.mtgshipping.app.orders.orderList.OrderListWrapperFragment"
        android:label="OrderListWrapperFragment"
        tools:layout="@layout/orders__list_wrapper">
        <action
            android:id="@+id/action_orderListWrapperFragment_to_orderDetailsFragment"
            app:destination="@id/orderDetailsFragment"/>
        <action
            android:id="@+id/action_orderListWrapperFragment_to_orderNewFragment"
            app:destination="@id/orderNewFragment"/>
        <action
            android:id="@+id/action_orderListWrapperFragment_to_orderUpdateFragment"
            app:destination="@id/orderUpdateFragment"/>
    </fragment>

    <fragment
        android:id="@+id/orderDetailsFragment"
        android:name="com.mtgshipping.app.orders.orderDetails.OrderDetailsFragment"
        android:label="OrderDetailsFragment"
        tools:layout="@layout/orders__order_details">
        <action
            android:id="@+id/action_orderDetailsFragment_to_orderUpdateFragment"
            app:destination="@id/orderUpdateFragment"/>
    </fragment>

    <fragment
        android:id="@+id/orderNewFragment"
        android:name="com.mtgshipping.app.orders.orderNew.OrderNewFragment"
        android:label="OrderNewFragment"
        tools:layout="@layout/orders__order_new">
        <action
            android:id="@+id/action_orderNewFragment_to_orderListWrapperFragment"
            app:destination="@id/orderListWrapperFragment"/>
    </fragment>

    <fragment
        android:id="@+id/orderUpdateFragment"
        android:name="com.mtgshipping.app.orders.orderUpdate.OrderUpdateFragment"
        android:label="OrderUpdateFragment"
        tools:layout="@layout/orders__order_update">
        <action
            android:id="@+id/action_orderUpdateFragment_to_orderListWrapperFragment"
            app:destination="@id/orderListWrapperFragment"/>
    </fragment>
</navigation>

I made some debug in NavController, it showed in line 746 NavDestination currentNode = mBackStack.isEmpty() ? mGraph : mBackStack.getLast().getDestination(); after device rotation mGraph is null, other private fields is also null. Maybe something prevents NavController to initialize properly. I can provide layouts and other code, if it will be need.

QuarK
  • 1,162
  • 2
  • 12
  • 27
  • 2
    I fixed navigation by updating Navigation Component to version 2.2.1. See this response: https://stackoverflow.com/a/58738512/4568679 – Slav Feb 07 '20 at 15:57

7 Answers7

24

Thanks to Slav's comment, he was right. I updated navigation module to 2.2.0 navigation_version = '2.2.0' in app's module build.gradle

implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"

After doing this problem is no longer appears, looks like that was a bug in navigation.

QuarK
  • 1,162
  • 2
  • 12
  • 27
  • 1
    it doesn't work for me :( https://stackoverflow.com/questions/60807361/still-have-error-no-current-navigation-node-even-after-using-navigation-2-2-1 – sarah Mar 23 '20 at 03:07
  • According maven page https://mvnrepository.com/artifact/android.arch.navigation/navigation-fragment the lates version is 1.0.0. How do you use the 2.2.0 version? – Irving Dev Jun 26 '20 at 04:42
  • @IrvingLóp This is old package, I use ktx version https://mvnrepository.com/artifact/androidx.navigation/navigation-fragment-ktx – QuarK Jun 27 '20 at 21:10
  • @sarah you probably forgot to change android.arch to androidx in the library name, basically change "android.arch.navigation:navigation-fragment-ktx" to ""androidx.navigation:navigation-fragment-ktx:" and the same thing for the other navigation library. – M.Ed Jan 17 '22 at 15:42
11

You can also fix it like this. In your host activity in manifest adding this atribute:

<activity android:name=".MainActivity"
        android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"

But the best way is change your dependencies for navigation from:

implementation "android.arch.navigation:navigation-fragment-ktx:$navigation_version"
implementation "android.arch.navigation:navigation-ui-ktx:$navigation_version"

to

implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
  • This was my issue, old dependencies. I think these "android.arch" dependencies are depreciated for "androidx" – ChrisMcJava Apr 12 '20 at 00:25
  • I guess if you're using `android.useAndroidX=true` option in your build, then you need `androidx.navigation` instead of `android.arch.navigation`. – Slav Apr 27 '20 at 18:50
  • Changing from "android.arch" to "androidx" solved my issue, many thanks – Super Symmetry Aug 11 '20 at 19:10
  • 1
    Yes this was helpful! I tried updating to 2.2.0 as suggested in the answer above, but I also had to switch from android.arch to androix. I'm fowlling some google codelabs that need to be updated! – Amber Aug 16 '20 at 21:45
  • Also in your project build.gradle change dependencies classpath to `"androidx.navigation:navigation-safe-args-gradle-plugin:$version_navigation"` – Gilbert Jan 02 '21 at 16:35
1

The problem for me was the version of lifecycle dependency

"androidx.lifecycle:lifecycle-extensions:$lifecycle_version

version '2.2.0' cause the problem, I returned to use '2.1.0'

lifecycle_version = '2.1.0'
Irving Dev
  • 389
  • 2
  • 8
1

In my case I got this exception after removing app:navGraph="@navigation/nav_main" in activity_main.xml:

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/container"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_main" />
CoolMind
  • 26,736
  • 15
  • 188
  • 224
1

My issue was that I was inflating graph only when savedInstanceState == null

Changing it to inflate every time onPostCreate fixed the issue

helvete
  • 2,455
  • 13
  • 33
  • 37
Hessesian
  • 51
  • 2
0

None of these solutions fixed my issue.

I fixed it by including my nested graph into the main graph.

I have a nav_main which includes a nav_sub_1.
nav_sub_1 also includes another sub graph, nav_sub_2
When I tried to start my activity by setting nav_sub_2, the IllegalStateException occured

java.lang.IllegalStateException: no current navigation node

But this would not happen by setting nav_main or nav_sub_1.

My main graph nav_main looks like this:

<navigation
    <fragment...>
    <include app:graph="@navigation/nav_sub_1
<navigation/>

and nav_sub_1:

<navigation
    <fragment...>
    <include app:graph="@navigation/nav_sub_2
<navigation/>

I included nav_sub_2 in nav_main and the issue was fixed!

<navigation
    <fragment...>
    <include app:graph="@navigation/nav_sub_1
    <include app:graph="@navigation/nav_sub_2
<navigation/>
Fartab
  • 4,725
  • 2
  • 26
  • 39
0

For me the fragment had the wrong parent. Changing this

   class MyFragment: DynamicNavHostFragment() ...

to this

   class MyFragment: Fragment() ...

Fixed that issue

dreinoso
  • 1,479
  • 17
  • 26