【问题标题】:OnBackPressedCallback is being called, but app is not going back正在调用 OnBackPressedCallback,但应用程序不会返回
【发布时间】:2019-10-24 06:04:24
【问题描述】:

我最近更新了我的依赖项,将OnBackPressedCallback 从接口更改为抽象类。

我已经根据新文档here 进行了设置,但我觉得事情并没有按应有的方式工作。

我的片段的OnCreate 看起来很像文档:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requireActivity().onBackPressedDispatcher.addCallback(this) {
            backPressed()
    }
}

当我按下返回按钮时,backPressed() 中的代码会运行,但没有任何反应。

我曾尝试从回调内部调用 handleBackPressed()requireActivity().onBackPressedDispatcher.onBackPressed()requireActivity().onBackPressed(),但这些都导致 StackOverflowError 因为它似乎递归地运行该回调。

必须有一些非常明显的东西我错过了......

【问题讨论】:

  • 你想做什么?如果您启用了OnBackPressedCallback,那么您已经说过您将处理后退按钮,所以当然没有其他操作。
  • 在回去之前我需要做一些事情。我现在可以做一些事情,但我似乎无法让它回去。
  • 如果您的活动覆盖 onBackPressed() 并且它对片段 onBackPress 有一些逻辑,那么请删除该部分,然后它将按预期工作

标签: android androidx android-jetpack android-architecture-navigation


【解决方案1】:

如果不再需要回调,您也可以删除回调而不是设置启用。我将它与这样的嵌套图一起使用,因为当您使用它的 NavHostFragment 在嵌套导航图中触摸时,它会将其从主片段返回堆栈中删除,而不是在嵌套导航图中打开最后一个片段。

   // Get NavHostFragment
    val navHostFragment =
        childFragmentManager.findFragmentById(R.id.nested_nav_host_fragment)

    // ChildFragmentManager of the current NavHostFragment
    val navHostChildFragmentManager = navHostFragment?.childFragmentManager

       val callback = object : OnBackPressedCallback(true) {

        override fun handleOnBackPressed() {

            val backStackEntryCount = navHostChildFragmentManager!!.backStackEntryCount


            if (backStackEntryCount == 1) {
                // We are at the root of nested navigation, remove this callback
                remove()
                requireActivity().onBackPressed()
            } else {
                navController?.navigateUp()
            }
        }
    }

    requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)

【讨论】:

    【解决方案2】:

    必须有一些非常明显的东西我错过了......

    在要求 Activity 处理后按之前,您忘记在片段中禁用自定义回调。

    适合我的解决方案:

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState); 
    
            final OnBackPressedCallback callback = new OnBackPressedCallback(true) {
                @Override
                public void handleOnBackPressed() {
                   if (/*situation to handle back pressing*/){
                    //here handle your backPress in your fragment
                    } else {
                       setEnabled(false); //this is important line
                       requireActivity().onBackPressed();
                    }
                }
            };
            requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
        }
    

    【讨论】:

      【解决方案3】:

      这对我有用 androidx.appcompat:appcompat:1.1.0

      requireActivity().onBackPressedDispatcher.addCallback(
              this,
              object : OnBackPressedCallback(true) {
                  override fun handleOnBackPressed() {
                      Log.d(TAG, "Fragment back pressed invoked")
                      // Do custom work here    
      
                      // if you want onBackPressed() to be called as normal afterwards
                      if (isEnabled) {
                          isEnabled = false
                          requireActivity().onBackPressed()
                      }
                  }
              }
          )
      

      【讨论】:

      • 不错的方法!
      【解决方案4】:

      当您注册OnBackPressedCallback 时,您将负责处理返回按钮。这意味着当您收到回调时,不会发生其他后按行为。

      如果您使用的是Navigation,您可以使用您的NavController 弹出回栈:

      requireActivity().onBackPressedDispatcher.addCallback(this) {
          backPressed()
          // Now actually go back
          findNavController().popBackStack()
      }
      

      【讨论】:

      • 嗯,好的。似乎我可能一直依赖早期 alpha 版本中的错误/意外行为。这实际上可以解释我正在解决的一些奇怪的事情。谢谢!
      • 这对我不起作用。问题是它在 alpha 中工作,但是当我更改为稳定版本时它现在显示错误。
      • @AbrahamMathew - 听起来您应该使用遇到问题的代码创建一个新问题。
      • @ianhanniballake - 我在单个活动和一些需要使用 BACK 按钮的片段中添加了回调。但是,我注意到片段的 addCallback() 必须在 onResume() 中调用。如果我在此生命周期回调之前添加并执行屏幕旋转,则 mOnBackPressedCallbacks 中的顺序不正确,活动是第一个(当然是相反的顺序)。现在,如果我不旋转屏幕,即使在 onViewCreated() 中,我也可以在片段中调用 addCallback(),并且按预期首先调用片段的回调。
      • @pigswig - 是的,你不能依赖活动的生命周期,正如this issue 中提到的那样,因为它没有嵌套在片段生命周期中。您当然可以在 Activity 中使用无生命周期版本,以确保它们始终位于堆栈的底部。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-26
      • 2016-05-20
      相关资源
      最近更新 更多