Я пытаюсь использовать Компонент архитектуры навигации (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>
Вы вращали устройство при возникновении этой ошибки?
Что касается первой ошибки, на основе вашего кода, когда пользователь выбирает «первый» или «настройки» из ящика, он переносится во фрагмент «первый» или «настройки» с помощью действия 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 будет назначен автоматически, но это не сработало для другой моей базы кода.
Что такое setupWithNavController?
2) Если авария происходит при изменении ориентации. Используйте нижеприведенное действие обновить модуль версии навигации до 2.2.0 или выше
implementation "androidx.navigation:navigation-fragment-ktx:2.2.0"
implementation "androidx.navigation:navigation-ui-ktx:2.2.0"
Вы знаете, как решить вторую проблему?
java.lang.IllegalStateException: no current navigation node?