Использование компонента архитектуры навигации с ящиком навигации

Я пытаюсь использовать Компонент архитектуры навигации (NavHostFragment) с Панель навигации (widget.NavigationView). Я получаю одну из следующих двух ошибок.

1) Это может произойти при выборе предмета из ящика несколько раз:

java.lang.IllegalArgumentException: navigation destination app.myDomain.navdrawertrials:id/action_rootFragment_to_settingsFragment is unknown to this NavController

2) Это происходит из моей реальной базы кода, которая настроена так же, как и в упрощенном примере ниже AFAICT. Почему бы не установить текущий узел навигации?

java.lang.IllegalStateException: no current navigation node

Упрощенный код

Основная деятельность

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)

        setupToolbar()
        setupNavDrawer()
        setupNavigation()
    }


    private fun setupToolbar() {
        setSupportActionBar( toolbar )
    }

    private fun setupNavigation() {
        val navController = findNavController( R.id.nav_host_fragment)

        setupActionBarWithNavController( navController, main_activity_drawer_layout )
    }

    private fun setupNavDrawer() {
        val toggle = ActionBarDrawerToggle(
                this,
                main_activity_drawer_layout,
                toolbar,
                R.string.navigation_drawer_open,
                R.string.navigation_drawer_close)

        main_activity_drawer_layout.addDrawerListener(toggle)
        toggle.syncState()


        nav_drawer.setNavigationItemSelectedListener {
            val navController = findNavController( R.id.nav_host_fragment )

            when (it.itemId) {
                R.id.nav_drawer_root_menu_item     -> navController.navigate(R.id.rootFragment)
                R.id.nav_drawer_first_menu_item    -> navController.navigate(R.id.action_rootFragment_to_firstFragment)
                R.id.nav_drawer_settings_menu_item -> navController.navigate(R.id.action_rootFragment_to_settingsFragment)
            }

            main_activity_drawer_layout.closeDrawer(GravityCompat.START)

            true
        }
    }

    override fun onSupportNavigateUp() = findNavController(R.id.nav_host_fragment).navigateUp()
}

main_activity.xml

<android.support.v4.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/main_activity_drawer_layout"
    android:layout_width = "match_parent"
    android:layout_height = "match_parent">

    <include
        layout = "@layout/main_activity_content"
        android:layout_width = "match_parent"
        android:layout_height = "match_parent" />

    <android.support.design.widget.NavigationView
        android:id = "@+id/nav_drawer"
        android:layout_width = "wrap_content"
        android:layout_height = "match_parent"
        android:layout_gravity = "start"
        android:fitsSystemWindows = "true"
        app:headerLayout = "@layout/nav_drawer_header"
        app:menu = "@menu/nav_drawer_menu" />

</android.support.v4.widget.DrawerLayout>

nav_drawer_menu.xml

<menu xmlns:android = "http://schemas.android.com/apk/res/android">

    <item
        android:id = "@+id/nav_drawer_root_menu_item"
        android:title = "To Root" />
    <item
        android:id = "@+id/nav_drawer_first_menu_item"
        android:title = "To First" />
    <item
        android:id = "@+id/nav_drawer_settings_menu_item"
        android:title = "To Settings" />
</menu>

main_activity_content.xml

<android.support.design.widget.CoordinatorLayout
    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:layout_width = "match_parent"
    android:layout_height = "match_parent"
    tools:context = ".MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width = "match_parent"
        android:layout_height = "wrap_content"
        android:theme = "@style/AppTheme">

        <android.support.v7.widget.Toolbar
            android:id = "@+id/toolbar"
            android:layout_width = "match_parent"
            android:layout_height = "?attr/actionBarSize"
            android:background = "?attr/colorPrimary" />

    </android.support.design.widget.AppBarLayout>

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

    <android.support.design.widget.FloatingActionButton
        android:id = "@+id/fab"
        android:layout_width = "wrap_content"
        android:layout_height = "wrap_content"
        android:layout_gravity = "bottom|end"
        android:layout_margin = "@dimen/fab_margin"
        app:srcCompat = "@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

nav_graph.xml

<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/rootFragment">

    <fragment
        android:id = "@+id/rootFragment"
        android:name = "app.anytune.navdrawertrials.RootFragment"
        android:label = "root_fragment"
        tools:layout = "@layout/root_fragment" >
        <action
            android:id = "@+id/action_rootFragment_to_firstFragment"
            app:destination = "@id/firstFragment" />
        <action
            android:id = "@+id/action_rootFragment_to_settingsFragment"
            app:destination = "@id/settingsFragment" />
    </fragment>
    <fragment
        android:id = "@+id/firstFragment"
        android:name = "app.anytune.navdrawertrials.FirstFragment"
        android:label = "first_fragment"
        tools:layout = "@layout/first_fragment" />
    <fragment
        android:id = "@+id/settingsFragment"
        android:name = "app.anytune.navdrawertrials.SettingsFragment"
        android:label = "settings_fragment"
        tools:layout = "@layout/settings_fragment" />
</navigation>

root_fragment.xml (другие узлы похожи на пустые фрагменты только с меткой)

<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 = ".RootFragment">

    <TextView
        android:layout_width = "match_parent"
        android:layout_height = "match_parent"
        android:text = "Root Fragment" />

</FrameLayout>

Вы знаете, как решить вторую проблему? java.lang.IllegalStateException: no current navigation node?

RediOne1 06.11.2018 15:05

Вы вращали устройство при возникновении этой ошибки?

IgorGanapolsky 07.11.2019 19:08
6
2
6 129
2

Ответы 2

Что касается первой ошибки, на основе вашего кода, когда пользователь выбирает «первый» или «настройки» из ящика, он переносится во фрагмент «первый» или «настройки» с помощью действия action_rootFragment_to_firstFragment или action_rootFragment_to_settingsFragment, но если вы попытаетесь снова выбрать «сначала» или «настройки» из ящика, нет действия action_rootFragment_to_firstFragment или action_rootFragment_to_settingsFragment внутри элемента firstFragment или settingsFragment внутри навигационного графика.

Решение - изменить:

when (it.itemId) { 
            R.id.nav_drawer_root_menu_item     -> navController.navigate(R.id.rootFragment) 
            R.id.nav_drawer_first_menu_item    -> navController.navigate(R.id.action_rootFragment_to_firstFragment) 
            R.id.nav_drawer_settings_menu_item -> navController.navigate(R.id.action_rootFragment_to_settingsFragment) 
        } 

к:

   when (it.itemId) { 
            R.id.nav_drawer_root_menu_item     -> navController.navigate(R.id.rootFragment) 
            R.id.nav_drawer_first_menu_item    -> navController.navigate(R.id.firstFragment) 
            R.id.nav_drawer_settings_menu_item -> navController.navigate(R.id.settingsFragment) 
        } 

Лучшее решение - связать пункты назначения с компонентами пользовательского интерфейса, управляемыми меню (в вашем случае - ящиком), изменить идентификатор элементов меню на такой же, как идентификаторы пунктов назначения, например:

<item
    android:id = "@+id/rootFragment"
    android:title = "To Root" />
<item
    android:id = "@+id/firstFragment"
    android:title = "To First" />
<item
    android:id = "@+id/settingsFragment"
    android:title = "To Settings" />

и добавить

 setupWithNavController(nav_view, navController )

внутри вашей основной деятельности, а не

nav_drawer.setNavigationItemSelectedListener {
        val navController = findNavController( R.id.nav_host_fragment )

        when (it.itemId) {
            R.id.nav_drawer_root_menu_item     -> navController.navigate(R.id.rootFragment)
            R.id.nav_drawer_first_menu_item    -> navController.navigate(R.id.action_rootFragment_to_firstFragment)
            R.id.nav_drawer_settings_menu_item -> navController.navigate(R.id.action_rootFragment_to_settingsFragment)
        }

        main_activity_drawer_layout.closeDrawer(GravityCompat.START)

        true
    }

Это означает, что navController имеет текущее состояние, и при вызове navController.navigate(R.id.action_to_something) navController должен уже находиться на начальном узле, откуда происходит действие. Имеет смысл. Это также могло объяснить мою вторую ошибку, когда я еще не установил текущее состояние navController на корневой узел. Однако я не вижу, как установить текущее состояние для корневого узла. Я думал, что узел Home будет назначен автоматически, но это не сработало для другой моей базы кода.

Jim Leask 11.07.2018 15:34

Что такое setupWithNavController?

IgorGanapolsky 07.11.2019 19:08

2) Если авария происходит при изменении ориентации. Используйте нижеприведенное действие обновить модуль версии навигации до 2.2.0 или выше

implementation "androidx.navigation:navigation-fragment-ktx:2.2.0"
implementation "androidx.navigation:navigation-ui-ktx:2.2.0"

Другие вопросы по теме