问题
在 Android 开发中,我们经常需要在页面之间传递数据。最近在做一个页面跳转并返回结果的功能时,遇到了一个棘手的问题:从 B 页面返回 A 页面时,A 页面始终收到 resultCode = 0(即 RESULT_CANCELED),明明在 B 页面已经设置了 setResult(RESULT_OK, intent)。
问题场景还原
先简单描述一下我的需求:
A 页面(管理页)通过按钮跳转到 B 页面(创建页)
在 B 页面操作完成后,点击返回键回到 A 页面,并携带返回数据
A 页面接收数据并提示用户
关键代码片段、
A 页面(接收结果):
// 注册返回结果监听器
private val intentActivityCreateResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
// 这里始终收到 resultCode = 0
if (result.resultCode == RESULT_OK) {
Log.e("Vehicle", "返回管理页面")
result.data?.let { data ->
val resultStr = data.getStringExtra("result")
ToastUtil.showMessageBottom(this, "从创建页面返回:$resultStr")
}
} else {
Log.e("Vehicle", "resultCode 异常:${result.resultCode}") // 总是打印 0
}
}
// 跳转按钮点击事件
binding?.btnCreateVehicle?.setOnClickListener {
val intent = Intent(this, ParamVehicleCreateActivity::class.java)
intentActivityCreateResult.launch(intent) // 跳转到 B 页面
}
B 页面(返回数据):
// 监听返回键
override fun onBackPressed() {
super.onBackPressed() // 先调用父类方法
// 后设置返回结果
val intent = Intent()
intent.putExtra("result", "修改完成")
setResult(RESULT_OK, intent)
finish()
}
运行后发现,A 页面的 resultCode 始终是 0,完全不符合预期。
问题根源:super.onBackPressed() 的执行顺序
排查发现,问题出在 B 页面的 onBackPressed() 方法执行顺序 上。
super.onBackPressed() 是父类 Activity 的方法,它的默认实现是 直接关闭当前页面(相当于调用 finish()),并且会自动设置 resultCode = RESULT_CANCELED(值为 0)。
在我最初的代码里:
先调用 super.onBackPressed() → 页面开始关闭,resultCode 被设为 0
再调用 setResult(RESULT_OK, intent) → 此时页面已经在关闭流程中,这个设置根本不会生效
简单说就是:页面都要关了,再设置返回结果已经来不及了。
解决方案:调整代码执行顺序
既然知道了问题原因,解决方法就很简单了:先设置返回结果,再执行页面关闭逻辑。
修改 B 页面的 onBackPressed() 方法:
override fun onBackPressed() {
// 第一步:先设置返回结果(必须在页面关闭前执行)
val intent = Intent()
intent.putExtra("result", "修改完成")
setResult(RESULT_OK, intent) // 关键:先设置结果
// 第二步:再执行关闭逻辑
super.onBackPressed() // 父类方法内部会调用 finish()
// 也可以直接用 finish() 替代,效果相同
// finish()
}
修改后重新运行,A 页面终于能收到 resultCode = -1(即 RESULT_OK),数据也能正常传递了!
扩展:其他返回场景的处理
除了物理返回键,用户还可能通过其他方式返回(比如顶部导航栏的返回按钮、手势返回),为了确保所有场景都能正确返回结果,我们需要额外处理这些情况。
1. 顶部导航栏返回按钮
如果页面使用了 ActionBar 或 Toolbar 的返回按钮,需要在 onOptionsItemSelected 中处理:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> { // 顶部导航栏返回按钮
// 同样先设置返回结果
val intent = Intent()
intent.putExtra("result", "修改完成")
setResult(RESULT_OK, intent)
finish() // 关闭页面
true
}
else -> super.onOptionsItemSelected(item)
}
}
2. 手势返回(全面屏手机)
如果应用支持手势返回(从屏幕左侧 / 右侧滑动返回),需要重写 onBackPressedDispatcher 的回调:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 处理手势返回
onBackPressedDispatcher.addCallback(this) {
val intent = Intent()
intent.putExtra("result", "修改完成")
setResult(RESULT_OK, intent)
finish()
}
}
总结
页面返回结果时,resultCode 总是 0 的问题,本质是 setResult() 与页面关闭逻辑的执行顺序 导致的。记住一个原则:
先调用 setResult() 设置返回结果,再执行页面关闭操作(super.onBackPressed() 或 finish())
正确的代码模板(B 页面):
// 物理返回键处理
override fun onBackPressed() {
// 1. 先设置返回结果
val intent = Intent()
intent.putExtra("key", "需要返回的数据")
setResult(RESULT_OK, intent)
// 2. 再关闭页面
super.onBackPressed() // 或直接 finish()
}