android-fragments 导航错误:无法从当前目标中找到操作/目标

cgh8pdjw  于 2022-11-14  发布在  Android
关注(0)|答案(3)|浏览(168)

我正在使用导航组件在两个片段之间导航。着陆片段具有回收程序视图,详细信息片段具有视图页。我正在使用回调侦听器从回收程序视图适配器触发导航操作。
要触发的动作是缩放事件,其库为ZoomHelper ZoomHelper
当事件发生时,应用程序崩溃并显示上述错误。
但是,它与onclick事件侦听器配合使用效果很好。

视图保持器

class CampaignListViewHolder<T : ViewBinding>(private val binding: T) : RecyclerView.ViewHolder(binding.root) {

    var campaignDetails: CampaignDetails? = null

    @SuppressLint("ClickableViewAccessibility")
    fun bindTo(campaignDetails: CampaignDetails?, position: Int, listener: ItemZoomListener) {
        this.campaignDetails = campaignDetails

        binding as CampaignItemLayoutBinding
        binding.campaignNameTv.text = campaignDetails?.name
        binding.campaignImageIv.load(campaignDetails?.image?.url) {
            crossfade(true)
            placeholder(R.drawable.westwing_placeholder)
        }
        ViewCompat.setTransitionName(binding.campaignImageIv, campaignDetails?.name)
        binding.root.setOnClickListener {
            if (campaignDetails != null) {
                listener.navigate(position)
            }
        }

        ZoomHelper.addZoomableView(binding.campaignImageIv)
        
        ZoomHelper.getInstance().addOnZoomScaleChangedListener(object :
                ZoomHelper.OnZoomScaleChangedListener {
                override fun onZoomScaleChanged(
                    zoomHelper: ZoomHelper,
                    zoomableView: View,
                    scale: Float,
                    event: MotionEvent?
                ) {
                    // called when zoom scale changed
                  
                    if (campaignDetails != null && scale > 1.4) {
                        listener.navigate(position)
                    }
                }
            })
    }
}

着陆碎片

class LandingFragment : Fragment(R.layout.fragment_landing), ItemZoomListener, FragmentUiStateListener {
    private val TAG by lazy { getName() }
    private val binding by viewBinding(FragmentLandingBinding::bind)
    private val campaignListViewModel: CampaignListViewModel by activityViewModels()
    lateinit var campaignViewAdapter: CampaignListViewAdapter
    lateinit var activityUiState: ActivityUiStateListener
    lateinit var fragmentUiUpdate: FragmentUiStateListener

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        campaignViewAdapter = CampaignListViewAdapter(this)
        fragmentUiUpdate = this
    }

    override fun onResume() {
        super.onResume()
        setupView()
        setUpData()
    }

    private fun setUpData() {
        setUpUiState(campaignListViewModel.campaignUiState, fragmentUiUpdate)
    }

    private fun setupView() {
        val orientation = checkOrientation()
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            binding.campaignLandscapeRcv?.apply {
                layoutManager = GridLayoutManager(requireContext(), 2)
                adapter = campaignViewAdapter
                addItemDecoration(ItemSpaceDecoration(8, 2))
            }
        } else {
            binding.campaignListRcv?.apply {
                layoutManager = LinearLayoutManager(requireContext())
                adapter = campaignViewAdapter
                addItemDecoration(ItemSpaceDecoration(8, 1))
            }
        }
    }

    override fun navigate(position: Int) {
        val direction = LandingFragmentDirections.actionLandingFragmentToCampaignDetailsFragment(position)
        goto(direction)
    }

我知道错误的原因之一可能是缩放事件多次调用导航控制器,但我不知道如何调试,以及什么可以是一种方法来解决这个问题。

soat7uwm

soat7uwm1#

正如你所猜测的,这个问题很可能是由navController被多次触发引起的。你可以通过“安全导航”来处理这个问题。下面是一个示例实现:

fun NavController.safelyNavigate(@IdRes resId: Int, args: Bundle? = null) = 
    try { navigate(resId, args) }
    catch (e: Exception) { Timber.e(e) }
}

然后,您可以按如下方式进行导航调用:

findNavController().safelyNavigate(your_id)

这样,对 NavController.navigate() 的任何额外调用都会被try和catch吸收。
防止崩溃:D

fwzugrvs

fwzugrvs2#

如果有人由于多次点击屏幕而遇到同样的问题。可以通过在导航前先检查当前目的地来解决

例如

片段A、B和C
在某些情况下,当单击片段A中导航到C的按钮时,从A导航到B可能会导致崩溃
为此,您应该首先检查当前目标,如下所示:

if(findNavController().currentDestination?.id==R.id.AFragment)
   findNavController().navigate(
   AFragmentDirections.actionAFragmentToCFragment()
 )
jtoj6r0c

jtoj6r0c3#

如果它被调用了两次,则可以在导航发生之前删除“ZoomHelper.OnZoomScaleChangedListener”。
我还没有测试下面的代码,但是你可以在这里探索这个库的代码https://github.com/Aghajari/ZoomHelper/blob/master/ZoomHelper/src/main/java/com/aghajari/zoomhelper/ZoomHelper.kt。你会发现一个名为'removeOnZoomScaleChangedListener'的方法,据我所知,它将删除一个类型为'ZoomHelper.OnZoomScaleChangedListener'的监听器。
前。

val onZoomScaleChangedListener = object :
                            ZoomHelper.OnZoomScaleChangedListener {
                            override fun onZoomScaleChanged(
                                zoomHelper: ZoomHelper,
                                zoomableView: View,
                                scale: Float,
                                event: MotionEvent?
                            ) {
                                // called when zoom scale changed
                                if (campaignDetails != null && scale > 1.4) {
              ZoomHelper.getInstance().removeOnZoomScaleChangedListener(onZoomScaleChangedListener) // Remove this event listener to avoid multiple triggers as you only need 1.
                                    listener.navigate(position)
                                }
                            }
                        }
        
      ZoomHelper.getInstance().addOnZoomScaleChangedListener(onZoomScaleChangedListener) // You can add the listener above like this.

相关问题