Android导航组件:回击导致NavController不同步

Android导航组件:回击导致NavController不同步,android,android-fragments,android-jetpack-navigation,Android,Android Fragments,Android Jetpack Navigation,我正在将一个应用程序从通过FragmentManager手动后台处理迁移到使用新的导航库。该应用程序由一个main活动组成,该活动有一个DrawerLayout,抽屉中有10-12个项目。当点击时,会发生一些片段操作,并显示一个新片段 在这个生产应用程序中有足够的代码,因此简单地删除旧的导航结构并将其整体移动到导航库是不可行的 相反,我所做的是逐抽屉项迁移抽屉项。例如,有一个叫做“支票存款”的功能,可以通过导航抽屉中的项目进行访问。当您点击该项目时,会显示一个新片段,您可以通过支票存款向导(如f

我正在将一个应用程序从通过
FragmentManager
手动后台处理迁移到使用新的导航库。该应用程序由一个
main活动
组成,该活动有一个
DrawerLayout
,抽屉中有10-12个项目。当点击时,会发生一些片段操作,并显示一个新片段

在这个生产应用程序中有足够的代码,因此简单地删除旧的导航结构并将其整体移动到导航库是不可行的

相反,我所做的是逐抽屉项迁移抽屉项。例如,有一个叫做“支票存款”的功能,可以通过导航抽屉中的项目进行访问。当您点击该项目时,会显示一个新片段,您可以通过支票存款向导(如flow)前进。到目前为止,我已经创建了一个新的
RootCheckDeposit
片段,它的
视图
由一个包含导航图的
FragmentContainerView
组成。然后,支票存款向导的整个“流程”在导航图中导航,导航图最终包含在
RootcheckDeposit

下面是该
RootCheckDeposit
片段的布局:

<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="androidx.navigation.fragment.NavHostFragment"
    app:defaultNavHost="true"
    app:navGraph="@navigation/check_deposit_graph" />
需要注意的是,当我们从
加载屏幕
转到
术语屏幕
登录屏幕
时,我们会弹出每个项目,因为我不希望用户能够“返回”加载屏幕或术语屏幕

我尝试过的事情:

  • 将导航图中的
    popup逻辑更改为指向实际导航图而不是目的地
  • 检查
    navController.popbackbackstack
    的结果是否为
    true
    false
    ,并采取相应的措施
我还梳理了实际的
NavController
代码,似乎正在发生的是,
NavController
在单击“后退”时会弹出其内部后退,但不会更改目的地,因为实际上没有其他目的地可去。然后,
NavController
似乎处于一种奇怪的不一致状态,它和当前显示的
Fragment
不正常/不指向同一事物

还有其他人成功地完成了这种迁移吗

编辑:我已经创建了一个回购协议,它有一个最小的项目来重新创建我遇到的崩溃:。这种回购类似于我正在开发的生产应用程序的结构。如果您点击幻灯片抽屉项目,然后继续点击屏幕中的文本,直到进入下一个示例片段,然后回击几次,再次点击文本,您将看到崩溃

我确信问题在于我如何设置导航库,我只是不确定正确的方法是什么,而不重写其余的应用程序导航,根据:

在任何给定的时间,只允许一个FragmentManager控制片段回栈。如果您的应用程序同时在屏幕上显示多个兄弟片段,或者如果您的应用程序使用子片段,则必须指定一个FragmentManager来处理应用程序的主导航

要在片段事务内部定义主导航片段,请调用该事务的方法,传入其childFragmentManager应具有主控制权的片段实例

如中所述,
app:defaultNavHost=“true”
正在
NavHostFragment
本身上为您调用
setPrimaryNavigationFragment()
,但您没有在父片段上调用
setPrimaryNavigationFragment()
。这意味着正在调用自动正确处理后退按钮的逻辑的none——实际上,您已经断开了从活动到父片段再到
NavHostFragment
的链。这会导致您在没有后台堆栈的情况下拦截“后退”按钮(当您弹出最后一个片段时,导航实际上不会删除它,否则在活动的退出动画运行时它将不存在)

因此,要解决此问题,您需要:

  • RootSlideshowFragment
    中删除您的
    OnBackPressedCallback
    。这是不必要的
  • main活动
    中的片段之间交换时,对新片段调用
    setPrimaryNavigationFragment()

  • “如果你回击什么都没发生-这很好”-不,那不好,这是一个你回击不正确的信号。您是否正在重写onBackPressed()
    并手动调用
    popBackStack()
    ?如果您已正确设置了片段层次结构,则不需要这样做。抱歉,我无法重现此错误。我使用了你的导航图和很多几乎是空的片段-一切都正常工作(特别是从LandingFragment向后按,允许我返回到CheckDepositorRoot片段之前的片段)。如果你需要更多的帮助,请考虑与问题分享behavior@ianhanniballake你说得对——我的感觉更像是“我对那种行为没意见”。我非常愿意接受这样一种观点,即我错误地设置了片段层次结构,我只是不确定正确的设置方式是什么。本质上,我不太明白当你点击导航堆栈中最后一个片段的“back”时会发生什么。什么都不应该发生吗?整个图表应该弹出吗?我不清楚。@BömachtBlau当你说“从LandingFragment返回允许我返回到CheckDepositorRootFragment之前的片段”时,在CheckDepositorRootFragment之前是什么?在我的应用程序中,这是导航堆栈的根,因此除非您更改导航抽屉项目(或退出应用程序),否则没有任何地方可以真正“返回”。我会试着做个mi
    <?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/check_deposit_graph"
        app:startDestination="@id/loadingFragment">
    
        <fragment
            android:id="@+id/loadingFragment"
            android:name="module.checkdeposit.loading.TermsLoadingFragment"
            android:label="@string/check_deposit_title"
            tools:layout="@layout/terms_loading_fragment" >
            <action
                android:id="@+id/action_loadingFragment_to_termsAndConditionsFragment"
                app:destination="@id/termsAndConditionsFragment"
                app:popUpTo="@id/loadingFragment"
                app:popUpToInclusive="true" />
            <action
                android:id="@+id/action_loadingFragment_to_depositOptionsFragment"
                app:destination="@id/depositLandingFragment"
                app:popUpTo="@id/loadingFragment"
                app:popUpToInclusive="true" />
        </fragment>
    
        <fragment
            android:id="@+id/termsAndConditionsFragment"
            android:name="module.checkdeposit.terms.TermsAndConditionsFragment"
            android:label="@string/check_deposit_terms_and_conditions"
            tools:layout="@layout/terms_and_conditions_fragment" >
            <action
                android:id="@+id/action_termsAndConditionsFragment_to_depositLandingFragment"
                app:destination="@id/depositLandingFragment"
                app:popUpTo="@id/termsAndConditionsFragment"
                app:popUpToInclusive="true" />
        </fragment>
    
        <fragment
            android:id="@+id/depositLandingFragment"
            android:name="module.checkdeposit.depositlanding.DepositLandingFragment"
            android:label="@string/check_deposit_title"
            tools:layout="@layout/deposit_landing_fragment" >
            <action
                android:id="@+id/action_depositLandingFragment_to_depositHistoryFragment"
                app:destination="@id/depositHistoryFragment" />
            <action
                android:id="@+id/action_depositLandingFragment_to_scanCheckFragment"
                app:destination="@id/scanCheckFragment" />
        </fragment>
    
        <fragment
            android:id="@+id/depositHistoryFragment"
            android:name="module.checkdeposit.deposithistory.DepositHistoryFragment"
            android:label="@string/check_deposit_deposit_history"
            tools:layout="@layout/deposit_history_fragment" />
    
        <fragment
            android:id="@+id/scanCheckFragment"
            android:name="module.checkdeposit.scancheck.ScanCheckFragment"
            android:label=""
            tools:layout="@layout/scan_check_fragment" />
    </navigation>
    
    navView.setNavigationItemSelectedListener { menuitem ->
        val newFragment = when (menuitem.itemId) {
            R.id.nav_home -> HomeFragment()
            R.id.nav_gallery-> GalleryFragment()
            else -> RootSlideshowFragment()
        }
        supportFragmentManager.beginTransaction()
            .replace(R.id.container, newFragment)
            .setPrimaryNavigationFragment(newFragment)
            .commit()
        true
    }