Fragment销毁时ActivityResultLauncher回调未触发,如何恢复处理状态?
解决Fragment内存不足重建后接收Activity返回结果的问题
方案1:为ActivityResultLauncher指定持久化Key
在Fragment注册Launcher时,使用带固定key的重载方法,让ActivityResultRegistry将未完成请求与key绑定,Fragment重建后用同一key注册的Launcher会自动承接之前的请求,接收返回结果。
修改MyFragment代码:
class MyFragment : Fragment(R.layout.my_fragment_layout) { companion object { private const val EXTRA_ID = "ExtraId" // 定义固定的Launcher标识Key private const val MY_RESULT_LAUNCHER_KEY = "MyResultActivityLauncher" fun newInstance(id: String) = MyFragment().apply { arguments = bundleOf(EXTRA_ID to id) } } private lateinit var launcher: ActivityResultLauncher<Intent> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 用固定Key注册Launcher launcher = registerForActivityResult( MY_RESULT_LAUNCHER_KEY, ActivityResultContracts.StartActivityForResult() ) { result -> if (result.resultCode == Activity.RESULT_OK) { Timber.i("Callback successful, received result after recreation") handleResult(result.data) } } } private fun handleResult(data: Intent?) { // 提取返回数据并处理业务逻辑 data?.getStringExtra("result_data")?.let { // 处理逻辑 } } fun launchMe() { val intent = Intent(requireContext(), MyResultActivity::class.java) launcher.launch(intent) } }
方案2:将ActivityResult逻辑托管到宿主Activity
把Launcher移到包裹Fragment的FragmentWrapperActivity中,Fragment通过接口请求启动Activity,Activity接收结果后通知当前Fragment实例,避免Fragment重建导致的回调丢失。
步骤1:修改FragmentWrapperActivity
class FragmentWrapperActivity : AppCompatActivity() { private lateinit var fragment: MyFragment private lateinit var binding: ActivityFragmentWrapperBinding private lateinit var launcher: ActivityResultLauncher<Intent> // 定义结果回调接口 interface OnMyResultReceivedListener { fun onMyResult(result: ActivityResult) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityFragmentWrapperBinding.inflate(layoutInflater) setContentView(binding.root) // 注册ActivityResultLauncher launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> // 通知当前Fragment处理结果 (fragment as? OnMyResultReceivedListener)?.onMyResult(result) } // 优先从FragmentManager恢复实例,而非每次新建 fragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as? MyFragment ?: MyFragment.newInstance("blah") supportFragmentManager.transact { replace(R.id.fragment_container, fragment) } } // 暴露给Fragment的启动方法 fun launchMyResultActivity(intent: Intent) { launcher.launch(intent) } }
步骤2:修改MyFragment实现接口
class MyFragment : Fragment(R.layout.my_fragment_layout), FragmentWrapperActivity.OnMyResultReceivedListener { companion object { private const val EXTRA_ID = "ExtraId" fun newInstance(id: String) = MyFragment().apply { arguments = bundleOf(EXTRA_ID to id) } } fun launchMe() { val intent = Intent(requireContext(), MyResultActivity::class.java) // 调用宿主Activity的方法启动目标页面 (requireActivity() as FragmentWrapperActivity).launchMyResultActivity(intent) } override fun onMyResult(result: ActivityResult) { if (result.resultCode == Activity.RESULT_OK) { Timber.i("Callback successful, received result from host Activity") handleResult(result.data) } } private fun handleResult(data: Intent?) { // 处理返回数据 } }
方案3:用ViewModel保存请求与结果状态
利用ViewModel的生命周期独立性,保存请求参数和返回结果,Fragment重建后通过观察ViewModel的状态来接续处理流程。
步骤1:创建ViewModel类
class MyFragmentViewModel : ViewModel() { // 用LiveData保存返回结果,支持Fragment重建后观察 val resultLiveData = MutableLiveData<ActivityResult?>() // 保存请求标识,用于业务逻辑匹配 var requestId: String? = null }
步骤2:修改MyFragment关联ViewModel
class MyFragment : Fragment(R.layout.my_fragment_layout) { companion object { private const val EXTRA_ID = "ExtraId" private const val MY_RESULT_LAUNCHER_KEY = "MyResultActivityLauncher" fun newInstance(id: String) = MyFragment().apply { arguments = bundleOf(EXTRA_ID to id) } } // 关联ViewModel,生命周期与Fragment所属Activity一致 private val viewModel: MyFragmentViewModel by viewModels() private lateinit var launcher: ActivityResultLauncher<Intent> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 保存请求标识到ViewModel viewModel.requestId = arguments?.getString(EXTRA_ID) launcher = registerForActivityResult( MY_RESULT_LAUNCHER_KEY, ActivityResultContracts.StartActivityForResult() ) { result -> viewModel.resultLiveData.value = result handleResult(result) } // 重建时观察结果,处理未完成的请求 viewModel.resultLiveData.observe(this) { result -> result?.let { if (it.resultCode == Activity.RESULT_OK) { Timber.i("Callback successful from ViewModel") handleResult(it) } } } } private fun handleResult(result: ActivityResult) { viewModel.requestId?.let { requestId -> // 结合请求标识处理对应业务逻辑 } } fun launchMe() { val intent = Intent(requireContext(), MyResultActivity::class.java) launcher.launch(intent) } }
内容的提问来源于stack exchange,提问作者Michael Dodd
相关产品推荐
相关产品推荐

