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个回答

129

将onBackPressed()替换为以下代码。

onBackPressedDispatcher.onBackPressed()

我正在使用targetSdk 33。 - Josh
5
对于片段 - requireActivity().onBackPressedDispatcher.onBackPressed() - Agilanbu
Xamarin 代码:OnBackPressedDispatcher.OnBackPressed(); - Gerry
这需要将Activity更改为androidx.activity.ComponentActivity。 - Matej Hlatky

111
根据您的API级别注册: 这需要至少使用appcompat:1.6.0-alpha03;当前版本为1.6.0-alpha04
 implementation 'androidx.appcompat:appcompat:1.6.0-alpha04'

// kotlin
import androidx.activity.addCallback

if (BuildCompat.isAtLeastT()) {
    onBackInvokedDispatcher.registerOnBackInvokedCallback(
        OnBackInvokedDispatcher.PRIORITY_DEFAULT
    ) {
        // Back is pressed... Finishing the activity
        finish()
    }
} else {
    onBackPressedDispatcher.addCallback(this /* lifecycle owner */, object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            // Back is pressed... Finishing the activity
            finish()
        }
    })
}

// ====================================================
/* Or for lambda simplicity: */
// ====================================================
if (BuildCompat.isAtLeastT()) {
    onBackInvokedDispatcher.registerOnBackInvokedCallback(
        OnBackInvokedDispatcher.PRIORITY_DEFAULT
    ) {
        // Back is pressed... Finishing the activity
        finish()
    }
} else {
    onBackPressedDispatcher.addCallback(this /* lifecycle owner */) {
        // Back is pressed... Finishing the activity
        finish()
    }
}


更新:

感谢 @ianhanniballake 的评论;即使在 API 级别 33+,您也可以直接使用 OnBackPressedDispatcher

当使用 Activity 1.6+ 时,OnBackPressedDispatcher 已经在内部使用 Android T 特定的 API。

因此,您只需执行以下操作:

// kotlin
import androidx.activity.addCallback

onBackPressedDispatcher.addCallback(this /* lifecycle owner */, object : OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
        // Back is pressed... Finishing the activity
        finish()
    }
})

// ====================================================
/* Or for lambda simplicity: */
// ====================================================
onBackPressedDispatcher.addCallback(this /* lifecycle owner */) {
    // Back is pressed... Finishing the activity
    finish()
}


// java
import androidx.activity.OnBackPressedCallback;

getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
    @Override
    public void handleOnBackPressed() {
        // Back is pressed... Finishing the activity
        finish();
    }
});

请注意不要重写 onBackPressed() 方法,否则会导致 onBackPressedDispatcher 的回调无法触发;可以参考这个答案来了解更多信息。

14
OnBackPressedDispatcher将在使用Activity 1.6+时,在内部已经使用了Android T特定的API,因此绝对没有理由直接使用Android T API——您可以在所有API级别上使用OnBackPressedDispatcher。请注意不改变原意。 - ianhanniballake
1
我看到的问题是现在你有两种处理后退按钮的方式,这有点混乱。有没有办法限制覆盖旧的 onBackPressed - Bitwise DEVS
@LuisA.Florit 刚刚更新了答案,并附上了Java代码片段。请查看。 - Zain
1
@Zain 这是我的错:我应该继承 AppCompatActivity 而不是 Activity。抱歉! - Luis A. Florit
如果你在一个片段中,就没有“finish()”方法。如果你添加了回调函数,但想继续正常的返回行为,我发现唯一的方法是禁用回调并再次点击返回。所以在回调函数内部:
this.isEnabled = false;
requireActivity().onBackPressedDispatcher.onBackPressed();
- phazei
显示剩余11条评论

42

通过各种最佳答案的结合,以下是一个解决方案:

1. 当您需要按返回按钮时,请复制以下内容:

注意:它将自动销毁您的活动。

button.setOnClickListener {
    onBackPressedDispatcher.onBackPressed()
}

2. 当你需要处理返回按钮按下事件时,请复制以下代码:

onBackPressedDispatcher.addCallback(this, object: OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
        // Whatever you want
        // when back pressed
        println("Back button pressed")
        finish()
    }
})

无法解决onBackPressedDispatcher问题 - undefined
也许你的代码出了点问题。那不是Kotlin吗? - undefined

32
只需替换
override fun onBackPressed() {
    super.onBackPressed() // Replace this deprecated line
}

使用

override fun onBackPressed() {
    onBackPressedDispatcher.onBackPressed() // with this line
}

更新

鉴于override fun onBackPressed()已被弃用,请将其替换为以下代码:

onBackPressedDispatcher.addCallback(this, object: OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
        println("Back button pressed")
        // Code that you need to execute on back press, e.g. finish()
  }
})

将上述代码添加到活动生命周期函数中,例如onCreate(savedInstanceState:)

4
我们需要将以上代码写在像onCreate()函数这样的方法内部。这就是我所缺少的,谢谢。 - Scamparelli

13
在Kotlin中,这种方式是可行的。
1- 删除onBackPressed()
2- 在onCreate(savedInstanceState: Bundle?)下面添加以下行:
 if (Build.VERSION.SDK_INT >= 33) {
        onBackInvokedDispatcher.registerOnBackInvokedCallback(
            OnBackInvokedDispatcher.PRIORITY_DEFAULT
        ) {
           
            exitOnBackPressed()
        }
    } else {
        onBackPressedDispatcher.addCallback(
            this,
            object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                  
                    Log.i("TAG", "handleOnBackPressed: Exit")
                    exitOnBackPressed()
                }
            })
    }

3- 定义一个新的函数来处理

fun exitOnBackPressed() {
}

7
你可以使用onBackPressedDispatcher
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
         
    }
})

在这里,“this” 指的是生命周期所有者(lifeCycleOwner)。


7
import android.os.Bundle
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder

class SampleActivity : AppCompatActivity(R.layout.activity_sample) {

    private val onBackPressedCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            showAppClosingDialog()
        }
    }

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

    private fun showAppClosingDialog() {
        MaterialAlertDialogBuilder(this)
            .setTitle("Warning")
            .setMessage("Do you really want to close the app?")
            .setPositiveButton("Yes") { _, _ -> finish() }
            .setNegativeButton("No", null)
            .show()
    }
}

5
使用onBackPressedDispatcher.onBackPressed()替代super.onBackPressed()。
override fun onBackPressed() {
  onBackPressedDispatcher.onBackPressed() 
}

5

对于Kotlin用户:

如果您正在尝试使用“新”方法调用默认的本地返回按钮功能,则可以在Activity中使用下面的代码。

this@MyActivity.onBackPressedDispatcher.onBackPressed()

例子:

myCloseButton.setOnClickListener { this@MyActivity.onBackPressedDispatcher.onBackPressed() }

上面的示例在按钮内设置了一个点击函数,使按钮的行为类似于本机Android返回按钮。

但是,如果您想自定义onBackPressedDispatcher,则可以按照下面的示例,在Activity中始终进行操作,因为此行为需要Activity上下文才能工作。

自定义OnBackPressed示例:

override fun onCreate(savedInstanceState: Bundle?) {
    
   val callback: OnBackPressedCallback = object : OnBackPressedCallBack(true) {
        override fun handleOnBackPressed() {
            //ToDo Implement your custom event here    
        }
    }

    this@MyActivity.onBackPressedDispatcher.addCallback(this@MyActivity, callback)
}

预期的结果是使任何onBackPressedDispatcher事件执行您想要的操作,或者根本不执行任何操作。但这并不推荐,因为您的用户可能会陷入一个屏幕中,无法使用手机的返回按钮。因此,请避免将handleOnBackPressed覆盖留空。尝试像这样做:
override fun handleOnBackPressed() {
    this@MyActivity.finish()
}

稍微多些细节会更好。 - Maruf Alam
我在这个答案中添加了一些细节。希望你们能好好利用。请随意在此线程回答中提出任何问题。 - Henrique Armelin Baggio Vieira

4
你可以使用OnBackInvokedCallback,如文档所述,并按照此处指南更新您的代码。OnBackInvokedCallback

详细了解: https://medium.com/@khadijahameed415/onbackpressed-deprecated-in-targetsdkversion-33-b4c27096bafe - Khadija Hameed

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