从带有 Jetpack 导航结果的 BottomSheetFragment 导航,出现崩溃“无法从当前目的地找到操作”

Posted

技术标签:

【中文标题】从带有 Jetpack 导航结果的 BottomSheetFragment 导航,出现崩溃“无法从当前目的地找到操作”【英文标题】:Navigating from BottomSheetFragment with Jetpack Navigation results with crash 'Action can not be found from current destination' 【发布时间】:2021-10-15 14:20:51 【问题描述】:

这个案例可能是一个独特的案例,因为我确实有一些复杂的导航逻辑,并且我正在使用扩展功能(我将在下面分享)。

想象有一个 Fragment(A) 打开一个 BottomSheetFragment(B) BottomSheetFragment(B) 里面有一个按钮。 点击按钮会关闭 BottomSheetFragment(B) 并导航到新的 Fragment(C)。

为了处理这种情况,我使用了 2 个扩展函数:

fun <T> Fragment.setNavigationResult(key: String, result: T) 
    findNavController().previousBackStackEntry?.savedStateHandle?.set(key, result)


fun <T> Fragment.getNavigationResult(key: String) = findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)

在BottomSheetFragment(B)中实现setNavigationResult

loginButton.setOnClickListener 
            dismiss()
            setNavigationResult(EVENT_CUSTOMER_SIGNUP_LOGIN, Event(true))
        

在 Fragment(A) 中实现getNavigationResult

getNavigationResult<Event<Boolean>>(EVENT_CUSTOMER_SIGNUP_LOGIN)?.observe(viewLifecycleOwner)  event ->
            event.value?.let 
                findNavController().navigate(R.id.openCustomerLogin)
            
        

应用程序崩溃并出现以下错误:

    java.lang.IllegalArgumentException: Navigation action/destination openFragmentC cannot be found from the current destination Destination(FragmentB)

这里我不明白的是,即使我之前打电话给dismiss,当前目的地仍然是BottomSheetFragment(B)

当我在导航到 FragmentC 之前添加延迟时,应用程序不会崩溃。

lifecycleScope.launch 
                    delay(250)
                    findNavController().navigate(R.id.openCustomerLogin)
                

我不喜欢delay 的解决方案,因为它不实用,而且在新的实现中很容易被遗忘。

抱歉,这篇文章很长,如果您能分享您对此的想法并为我提供帮助,我将不胜感激。

【问题讨论】:

【参考方案1】:

我已经实现如下

点击按钮时假设底部表格的代码如下

 private fun closeBottomSheet() 
        findNavController().previousBackStackEntry?.savedStateHandle?.set("refresh", true)
        findNavController().navigateUp()
    

片段A的以下代码

val observer = LifecycleEventObserver  _, event ->
            if (event == Lifecycle.Event.ON_RESUME
                && navBackStackEntry.savedStateHandle.contains("refresh")
            ) 
                val result = navBackStackEntry.savedStateHandle.get<Boolean>("refresh")
                if (result!!) 
                    result.run 
                        // whatever you do , go from fragment A to Fragment C
                        navBackStackEntry.savedStateHandle.remove<Boolean>("refresh")
                    
                
            
        
    

并检查您是否在 navigation.xml 中的片段 A 中定义了操作

【讨论】:

嗨 gaurav gupta,我尝试使用 findNavController().navigateUp() 而不是解雇。它仍然会立即崩溃(250)。片段 A 具有导航到片段 C 的定义,但片段 B 没有。 如果结果为空,你的应用程序会在这种情况下崩溃,我不会使用这样的代码。你应该改为result?.run ... 在 null 或 not null 的情况下,你编写这样的代码 result?.let result -> // 不管你做什么

以上是关于从带有 Jetpack 导航结果的 BottomSheetFragment 导航,出现崩溃“无法从当前目的地找到操作”的主要内容,如果未能解决你的问题,请参考以下文章

带有片段和 Jetpack 导航的 Viewpager2:恢复片段而不是重新创建它们

Android Jetpack导航,另一个主机片段内的主机片段

在 Scaffold Jetpack Compose 内的特定屏幕上隐藏顶部和底部导航器

使用Android Jetpack导航时如何防止导航

带有 Jetpack Navigation 的 BottomNavigationView 未正确显示活动菜单指示器

如何在使用Android Jetpack导航时禁用导航图标