IllegalStateException: Activity does not have a NavController set on [duplicate]
B

1

8

I try to write an Android app which uses the Navigation Component from androidx, a toolbar and a drawer layout to slide in a setting menu from the left. I followed the guides Get started with the Navigation component and tried to add a top app bar and a setting using this guide Update UI components with NavigationUI.

When my apps starts, the following exception is thrown:

java.lang.IllegalStateException: Activity ....MainActivity@e686cd8 does not have a NavController set on 2131230993

Side remark: If I open nav_graph.xml in design mode, the hosts pane reports "No NavHostFragments found. This nav graph must be referenced from a NavHostFragment in a layout in order to be accessible." Maybe this error and the exception are related and share the same root cause. However, my navigation graph is referenced by a NavHostFragment though, see below.

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:fitsSystemWindows="true"
  tools:context=".MainActivity">

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/main_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="?attr/actionBarTheme" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />
  </LinearLayout>

  <com.google.android.material.navigation.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/drawer_view"
    app:headerLayout="@layout/nav_header" />
</androidx.drawerlayout.widget.DrawerLayout>

This layout

  • contains a FragmentContainerView
  • references @navigation/nav_graph (pasted below)
  • contains a NavigationView
  • references @layout/nav_header (pasted below)
  • references @menu/drawer_view (pasted below)

nav_header.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.widget.LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="192dp"
  android:background="?attr/colorPrimaryDark"
  android:gravity="bottom"
  android:padding="16dp"
  android:theme="@style/ThemeOverlay.AppCompat.Dark">

  <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/app_name"
    android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
</android.widget.LinearLayout>

drawer_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <group android:checkableBehavior="single">
    <item
      android:id="@+id/nav_home"
      android:icon="@drawable/ic_home"
      android:title="@string/home"/>
    <item
      android:id="@+id/nav_settings"
      android:icon="@drawable/ic_settings"
      android:title="@string/settings" />
  </group>
</menu>

fragment_home.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".HomeFragment"/>

This fragment is referenced by nav_graph (pasted below) as the home fragment (start destination).

nav_graph.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/nav_graph"
  app:startDestination="@id/homeFragment">

  <fragment
    android:id="@+id/homeFragment"
    android:name="de.mhnnet.lychee4android.HomeFragment"
    android:label="fragment_home"
    tools:layout="@layout/fragment_home" />
</navigation>

MainActivity.java:

protected void onCreate( Bundle savedInstanceState ) {
  super.onCreate( savedInstanceState );
  setContentView( R.layout.activity_main );

  NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment );
  AppBarConfiguration appBarConfiguration =
    new AppBarConfiguration.Builder(navController.getGraph()).build();
  Toolbar toolbar = findViewById( R.id.main_toolbar );
  NavigationUI.setupWithNavController( toolbar, navController, appBarConfiguration );
}

Further Remarks:

I already found some tips which says that androidx.fragment.app.FragmentContainerView should be replaced by fragment. However, this feels wrong as the linter recommends to use FragmentContainerView instead of fragment and the official Android docs use FragmentContainerView, too.

Bumboat answered 21/2, 2021 at 16:12 Comment(0)
S
13

Okay to get Nav Controller in your activity either replace your

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

with

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

But as the lint suggest to change fragment with FragmentContainerView Use the below code to get Nav Controller in your activity.


        NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);

        if (navHostFragment != null) {

            NavController navController = navHostFragment.getNavController();

            // Setup NavigationUI here

        }

Salinasalinas answered 21/2, 2021 at 16:33 Comment(2)
But this basically means that the original Google Android Docs are wrong. Also, the post which is linked above says that findFragmentById() must be used, because findNavController does not work in onCreate(). But the latter is what the Google Android Docs recommend.Bumboat
It's a bug look at this issuetracker.google.com/issues/142847973Salinasalinas

© 2022 - 2024 — McMap. All rights reserved.