You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 23:10:43