【问题标题】:NavController crashes upon orientation changeNavController 在方向更改时崩溃
【发布时间】:2019-08-16 15:07:34
【问题描述】:

我不确定我在这里做错了什么。简单的设置,带有由内部底部栏控制的片段的单个活动,到目前为止一切都很好。开始片段有一个按钮,里面应该导航到另一个片段。

这是我的片段类中按钮的 onclicklistener:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    add_step_fab.setOnClickListener {
        Navigation.findNavController(view).navigate(R.id.fragmentAtoB)
    }
}

这是我在 navigation.xml 中的操作:

<fragment android:id="@+id/navigation_main" android:name="com.test.test.fragments.AFragment"
          android:label="Fragment A" tools:layout="@layout/fragment_a">
    <action android:id="@+id/fragmentAtoB"
            app:destination="@id/fragmentB" app:enterAnim="@anim/nav_default_enter_anim"
            app:exitAnim="@anim/nav_default_exit_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim"
            app:popExitAnim="@anim/nav_default_pop_exit_anim"/>
</fragment>

导航有效,但我得到标准

java.lang.IllegalArgumentException: navigation destination com.test.test:id/fragmentAtoB is unknown to this NavController

在旋转屏幕、拆分应用程序或有时看似随机的情况下单击按钮时出错。好像和配置变化有关?

编辑: 我也尝试过使用

val clickListener: View.OnClickListener = Navigation.createNavigateOnClickListener(R.id.fragmentAtoB)
    add_step_fab.setOnClickListener(clickListener)

与上述问题相同。

检查我是否真的在同一个片段中,正如一些为有相同异常(但出于不相关原因)的用户所建议的那样,例如:

if (controller.currentDestination?.id == R.id.navigation_main) {
            controller.navigate(R.id.fragmentAtoB)
        }

也没有帮助。

【问题讨论】:

    标签: android kotlin android-jetpack android-jetpack-navigation


    【解决方案1】:

    在应用正常运行数月后,我最近也遇到了这种情况。我最初将导航添加到使用“MainActivity”类的应用程序,然后从菜单启动其他活动(而不是让导航组件在单个活动的片段之间导航)。

    因此,应用程序的组织方式使 MainActivity 是“中心”,菜单选项中的选择会导致启动其他活动,当用户从它们返回时,它们会回到 MainActivity - 所以一个纯粹的“中心( MainActivity) 和spoke (5 其他活动)”模型。

    在 MainActivity.onCreate() 中调用 setupNavigation() 方法,最初看起来像:

    private void setupNavigation() {
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    
        drawerLayout = findViewById(R.id.drawer_layout);
    
        // This class implements the listener interface for the NavigationView, handler is below.
        NavigationView navigationView = findViewById(R.id.nav_view);
        navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);
        NavigationUI.setupWithNavController(navigationView, navController);
    
        // MainActivity implements the listener for navigation events
        navigationView.setNavigationItemSelectedListener(this);
    
    }
    

    正如我所提到的,即使在最近发生配置更改时,它也能正常工作。即使只是将 MainActivity 上的配置从纵向更改为横向也会导致异常:

    ComponentInfo{com.reddragon.intouch/com.reddragon.intouch.ui.MainActivity}: java.lang.IllegalStateException: You must call setGraph() before calling getGraph()
    

    我发现我必须添加这一行:

    navController.setGraph(R.navigation.nav_host);
    

    在 Naviation.findNavController() 调用之后,它就可以很好地处理配置更改。

    【讨论】:

    • 在导航文件中使用setGraph 方法也为我解决了这个问题!
    • 是的,这确实是在 ViewPager (stackoverflow.com/questions/52630267/…) 的一个页面内导航的情况下的解决方案。谢谢!!
    • “在 Naviation.findNavController() 调用之后,它处理了配置更改就好了。” - 这是正确的!!!
    【解决方案2】:

    配置更改后,片段或活动暂时超出范围,然后执行 onResume() 覆盖。如果你有任何在 onCreate() 或 onViewCreated() 中初始化的东西,那么这些变量可能已经超出范围,现在是空值。所以,我通常有一个叫做RestoreAll()的方法,它负责实例化代码使用的所有对象,我从onResume()中调用这个方法,这样每次配置发生变化时,所有的本地对象都会重新- 实例化。

    【讨论】:

    • 必须有一种方法可以使用 jetpack 以生命周期感知的方式处理 onclicks 吗?毕竟,大多数 jetpack 架构组件的全部前提是停止考虑片段和活动生命周期
    • 我们将不得不等待更熟悉喷气背包架构的人的来信。我刚刚在我的所有应用程序开发中都使用了这种保险方法,并且从那以后没有任何问题。
    • 所以我刚刚查看了一些示例,它们与 oncreateview 中的导航完美配合。这里发生了一些非常奇怪的事情,所以我想我明天会用更多的代码来赏金
    • 改用 Android ViewModel
    【解决方案3】:

    更改配置后导航控制器回栈出现问题。尝试这个: https://stackoverflow.com/a/59987336/5433148

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多