RegisterForActivityResult API:启动Activity遇配置变更无法返回结果
解决Activity配置变更后无法返回结果的问题
问题场景
现有Activity A与Activity B的实现逻辑:
- Activity A 通过
registerForActivityResult启动Activity B,并接收其返回的Intent数据 - Activity B 的RecyclerView列表项点击时,设置返回结果并关闭自身
- 应用已锁定竖屏避免旋转配置变更,但需适配字体/显示大小调整引发的UI重绘配置变更
- 当Activity B因配置变更销毁重建后,点击列表项无法将结果返回给Activity A,且A、B的ViewModel无关联
解决方案
方案一:避免Activity B因配置变更销毁重建
在AndroidManifest.xml中为Activity B添加configChanges属性,指定需要手动处理的配置项,让系统在这些配置变更时不销毁重建Activity,而是调用onConfigurationChanged方法:
<activity android:name=".ActivityB" android:configChanges="fontScale|screenSize|smallestScreenSize|layoutDirection" <!-- 其他原有属性 --> />
之后在Activity B中重写onConfigurationChanged方法,处理UI适配逻辑:
override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // 根据新配置更新UI,比如刷新RecyclerView内容 recyclerView.adapter?.notifyDataSetChanged() }
优点:直接规避配置变更导致的Activity销毁重建问题;缺点:需要手动处理所有指定配置项的UI适配逻辑。
方案二:用ViewModel保存待返回结果状态
利用ViewModel的生命周期独立性(不受Activity配置变更影响),保存待返回的结果,确保Activity B重建后能继续返回结果:
- 为Activity B创建ViewModel:
class ActivityBViewModel : ViewModel() { // 保存待返回的结果码和Intent var pendingResult: Pair<Int, Intent>? = null }
- 在Activity B中获取ViewModel:
private val viewModel by viewModels<ActivityBViewModel>()
- 列表项点击时,将结果存入ViewModel并关闭:
// RecyclerView列表项点击事件处理 holder.itemView.setOnClickListener { val targetData = // 获取当前列表项的数据 val resultIntent = Intent().apply { putExtra("key", targetData) } // 将结果存入ViewModel viewModel.pendingResult = Pair(Activity.RESULT_OK, resultIntent) finish() }
- 在Activity B的
onCreate中检查待返回结果,若存在则立即返回:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 初始化视图逻辑... // 检查是否有待返回的结果,若有则立即返回给Activity A viewModel.pendingResult?.let { (code, intent) -> setResult(code, intent) finish() } }
优点:ViewModel自动处理状态保留,无需手动序列化数据;缺点:仅适用于Activity未被系统回收的场景。
方案三:用SavedInstanceState持久化结果状态
如果需要应对进程被杀的极端情况,可结合SavedInstanceState持久化待返回结果:
- 在Activity B中定义常量和成员变量:
companion object { private const val KEY_RESULT_CODE = "result_code" private const val KEY_RESULT_INTENT = "result_intent" } private var pendingResultCode = Activity.RESULT_CANCELED private var pendingResultIntent: Intent? = null
- 重写
onSaveInstanceState保存结果状态:
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // 仅当存在待返回结果时才保存 if (pendingResultCode != Activity.RESULT_CANCELED && pendingResultIntent != null) { outState.putInt(KEY_RESULT_CODE, pendingResultCode) outState.putParcelable(KEY_RESULT_INTENT, pendingResultIntent) } }
- 在
onCreate中恢复状态并返回结果:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 初始化视图逻辑... savedInstanceState?.let { pendingResultCode = it.getInt(KEY_RESULT_CODE, Activity.RESULT_CANCELED) pendingResultIntent = it.getParcelable(KEY_RESULT_INTENT) // 若恢复到待返回结果,立即返回给Activity A if (pendingResultCode != Activity.RESULT_CANCELED && pendingResultIntent != null) { setResult(pendingResultCode, pendingResultIntent) finish() } } }
- 列表项点击时设置待返回状态:
holder.itemView.setOnClickListener { val targetData = // 获取当前列表项的数据 pendingResultIntent = Intent().apply { putExtra("key", targetData) } pendingResultCode = Activity.RESULT_OK finish() }
优点:即使进程被杀也能恢复状态;缺点:需要手动处理数据的序列化/反序列化,仅支持Parcelable类型的数据。
内容的提问来源于stack exchange,提问作者MajinKenn
相关产品推荐
相关产品推荐

