onBackPressed()被弃用。有什么替代方法?

154

我已将targetSdkVersioncompileSdkVersion升级到33

现在我收到一个警告,告诉我onBackPressed已经被弃用。

我看到建议使用android.window.OnBackInvokedCallbackandroidx.activity.OnBackPressedCallback来处理返回导航。有人可以帮助我使用更新的方法吗?

示例

onBackPressedDeprecated

使用案例
我在onBackPressed()方法中使用if (isTaskRoot) {}来检查当前活动是否是活动堆栈中的最后一个。
override fun onBackPressed() {
    if (isTaskRoot) { // Check whether this activity is last on the activity stack. (Check whether this activity opened from a Push Notification.)
        startActivity(Intent(mContext, Dashboard::class.java))
        finish()
    } else {
        finishWithResultOK()
    }
}

1
如果你只是调用 super.onBackPressed(),那么你可以完全删除这个方法,因为你没有编写任何自定义的返回行为。如果你正在编写自定义的返回行为,请展示你的代码。 - ianhanniballake
@ianhanniballake,我在onBackPressed()中使用if (isTaskRoot) {}来检查活动是否是活动堆栈上的最后一个。我也更新了问题。 - Rumit Patel
你不应该在任何API级别上这样做。请包含您的代码。 - ianhanniballake
点击推送通知后,产品详细页面会打开。如果应用程序已关闭,现在用户通过点击推送通知进入产品详细页面。然后,当用户点击“返回”按钮时,用户不应直接退出应用程序。对于这种情况,我使用 onBackPressed() - Rumit Patel
1
你解决了 isTaskRoot 条件吗?大多数答案似乎都集中在琐碎的用例上。 - TWiStErRob
显示剩余4条评论
19个回答

3

奖励: 按下返回键时关闭DrawerLayout,使用以下方式(根据这个I/O讲座

val callback = onBackPressedDispatcher.addCallback(this, false) {
    binding.drawerLayout.closeDrawer(GravityCompat.START)
}
            
binding.drawerLayout.addDrawerListener(object : DrawerListener {  
        
    override fun onDrawerOpened(drawerView: View) {
        callback.isEnabled = true
    }
        
    override fun onDrawerClosed(drawerView: View) {
        callback.isEnabled = false
    }

    override fun onDrawerSlide(drawerView: View, slideOffset: Float) = Unit    
    override fun onDrawerStateChanged(newState: Int) = Unit
})

3

这是一个扩展函数,用于在活动中实现OnBackPressedCallback功能。

fun AppCompatActivity.addOnBackPressedDispatcher(onBackPressed: () -> Unit = { finish() }) {
    onBackPressedDispatcher.addCallback(
        this,
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                onBackPressed.invoke()
            }
        }
    )
}

使用方法:

addOnBackPressedDispatcher {
    //doSomething()
}

有没有Xamarin C#的代码示例?我看到了一个.NET的示例,但它使用了一个私有类,我无法编译它。我尝试安装一些新的Nuget类,但那只是陷入了一个死胡同。有没有简单的方法来替换我的OnBackPressed调用?谢谢。 - fbs419
https://dev59.com/dXkPtIcB2Jgan1znnp1t - Abdullah Javed
2
该函数最好被称为 addOnBackPressedCallback(),因为这就是它的作用。只有一个调度程序处理所有回调。 - Ridcully

2
首先,我们需要添加一个回调对象,因为onBackPressedDispatcher.onBackPressed()会按照它们被添加的相反顺序触发当前已添加的回调。 所以在添加回调之后,我们才应该调用onBackPressed()方法。
以下是Kotlin代码示例:
 onBackPressedDispatcher.addCallback(this,object :OnBackPressedCallback(true){
            override fun handleOnBackPressed() {
                Log.i("TAG","back has been called")
                finish()
            }
        })

onBackPressedDispatcher.onBackPressed()

1
我通过简单地向AppCompatActivity添加一个扩展来解决这个问题。
fun AppCompatActivity.onBackButtonPressed(callback: (() -> Unit)? = null){
    val onBackPressed: OnBackPressedCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            callback?.let { callback() } ?: run { finish() }
        }
    }
    this.onBackPressedDispatcher.addCallback(this, onBackPressed)
}

所以我可以通过两种方式使用它,一种是调用"onBackButtonPressed"。
1- 实现返回键按下来结束活动。
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // implement back pressed
    onBackButtonPressed()
}

2- 处理返回按钮点击事件:
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // implement back pressed
    onBackButtonPressed {
        // handle back pressed click here,

    }
}

1
大多数答案在想要关闭活动时调用 `finish()`。对于大多数情况,这样做效果很好,但在某些情况下不起作用。例如,在Android 13中,当你按下堆栈中的最后一个活动上的返回按钮并返回到主屏幕时,`onDestroy()` 不会立即被调用,应用程序仍然在内存中。如果你立即重新打开应用程序,它将从 `onStart()` 开始。
因此,在某些情况下,最好让系统处理关闭应用程序,或者换句话说,让 `super.onBackPressed()` 发生。
替代方法如下:
override fun onBackPressed() {
    if(showPopUpBeforeClosing){
        showDialog()
    } else {
        super.onBackPressed()
    }
}

做这个 -

onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
        if (showPopUpBeforeClosing) {
            showDialog()
        } else {
            //Removing this callback
            remove()
            onBackPressedDispatcher.onBackPressed()
        }
    }
})

如果你在onBackPressedDispatcher中添加一个回调函数,并调用onBackPressedDispatcher.onBackPressed(),它总是会调用handleOnBackPressed()。没有像onSuperBackPressed()这样的方法,让系统知道在完成后自己处理backPress。如果你不添加回调函数,那么系统会自行处理,但如果你添加了回调函数,那么调用onBackPress将会调用handleOnBackPressed()。所以我们要做的是,在处理完back-press后,你需要callback.remove()来移除回调函数,现在当你执行onBackPressedDispatcher.onBackPressed()时,它将不会调用handleOnBackPressed(),而是像系统一样处理back-press,相当于super.onBackPressed()

很确定这是错误的。系统看到回调已启用(根据true),因此无法播放预测的返回导航。你正在解决废弃问题,但解决方法不正确... 当你有一个新的showPopUpBeforeClosing值时,应该更新回调的isEnabled属性(如果是响应式/基于状态的话最简单)。像if (showPopUpBeforeClosing) {这样的代码在新的onBackPressedCallback世界中不应该存在。 - undefined

0
重写 BottomSheets 的 onDismiss() 函数。
override fun onDismiss(dialog: DialogInterface) {
   super.onDismiss(dialog)
   //TODO your logic.
   }

0

设置覆盖默认行为的能力: (从Activity onCreate()中调用setupBackPressedHandling()):

  private fun setupBackPressedHandling() {
        onBackPressedDispatcher.addCallback(this) {
            if (!backPressHandled())
                invokeDefaultBackPressedHandling()
        }
    }

open fun backPressHandled(): Boolean = false

全局扩展函数:

  fun AppCompatActivity.invokeDefaultBackPressedHandling(navController: NavController?) {
    when(navController) {
        null -> {
            if (!supportFragmentManager.isStateSaved && !supportFragmentManager.popBackStackImmediate())
                finish()
        }
        else -> {
            if (!navController.popBackStack())
                finish()
        }
    }
}

0
你可以使用onBackPressedDispatcher。以下是一个示例:
val back = this.onBackPressedDispatcher
back.addCallback(this, object : OnBackPressedCallback(true){
    override fun handleOnBackPressed() {
        //println("back pressed")
    }
})

-2

使用方法如下:

override fun onClick(v: View?) {
    when (v?.id) {
        R.id.iv_back -> onBackPressedMethod()
    }
}

现在创建处理返回事件的方法

private fun onBackPressedMethod(){
    if (Build.VERSION.SDK_INT >= 33) {
        onBackInvokedDispatcher.registerOnBackInvokedCallback(
            OnBackInvokedDispatcher.PRIORITY_DEFAULT) {
            // back button pressed... finishing the activity
            finish()
        }
    } else {
        onBackPressedDispatcher.addCallback(
            this,
            object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                // back button pressed... finishing the activity
                finish()
                }
            })
    }
}

就这样!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接