有时,我想自己处理用户按下的后退按钮。我的(示例)代码如下所示:
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.test)
}
override fun onBackPressed() {
if (checkSomeCondition()) {
// do nothing
} else {
super.onBackPressed()
}
}
private fun checkSomeCondition() = false
}
Run Code Online (Sandbox Code Playgroud)
当按下返回时我会收到通知,然后我决定是否要处理它,或者让系统通过调用 来处理它super.onBackPressed()。
由于 onBackPressed() 现已弃用,我使用以下方法替换它OnBackPressedDispatcher:
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.test)
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (checkSomeCondition()) {
// do nothing
} else {
onBackPressedDispatcher.onBackPressed()
}
}
})
}
private fun checkSomeCondition() = false
}
Run Code Online (Sandbox Code Playgroud)
这段代码的问题是:通过调用onBackPressedDispatcher.onBackPressed(),我调用了自己的回调,创建了一个无限循环,而不是像我那样将其交给系统super.onBackPressed()。
当暂时禁用我的回调时,可以避免这种情况,例如:
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (checkSomeCondition()) {
// do nothing
} else {
this.isEnabled = false
onBackPressedDispatcher.onBackPressed()
this.isEnabled = true
}
}
})
Run Code Online (Sandbox Code Playgroud)
但这看起来相当尴尬,而且似乎并不是有意为之。
OnBackPressedDispatcher让我自己处理后退按钮或将其交给系统的正确用法是什么?
PS:我已经看到了关于弃用 onBackPressed 的问题,但它没有回答我更具体的问题。
根据“系统后退基础知识”视频,预测后退手势的全部要点是提前了解要处理的后退内容。
这意味着您永远不应该拥有即时逻辑,例如checkSomeCondition作为调用的一部分handleOnBackPressed。
相反,正如自定义后退导航文档中所述,只要您用于签入的条件发生变化,您就应该提前更新isEnabled状态。这可确保仅当条件为真时才调用回调,而当条件为假时则禁用回调,从而允许发生默认行为。OnBackPressedCallback checkSomeCondition
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.test)
// Instead of always setting enabled to true at the beginning,
// you need to check the state ahead of time to know what the
// initial enabled state should be
val isConditionAlreadySet = checkSomeCondition()
val callback = object : OnBackPressedCallback(
isConditionAlreadySet
) {
override fun handleOnBackPressed() {
// Since you've handled isEnabled correctly, you know
// your condition is set correctly here, so you can
// unconditionally do what you need to do to handle back
}
}
// This is the key part - now you know ahead of time
// when the condition changes, which lets you control
// when you want to handle back or not
setOnSomeConditionChangedListener { isConditionMet ->
callback.isEnabled = isConditionMet
}
onBackPressedDispatcher.addCallback(this, callback)
}
private fun checkSomeCondition() = false
private fun setOnSomeConditionChangedListener(
(isConditionMet: Boolean) -> Unit
) {
// The implementation here will depend on what
// conditions checkSomeCondition() actually depends on
}
}
Run Code Online (Sandbox Code Playgroud)