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

Activity横竖屏切换时如何保留Fragment实例及Retrofit查询结果

横竖屏切换Fragment数据丢失解决方案

核心问题分析

你当前遇到的问题主要由三个错误实现导致:

  • ViewModel作用域不统一:MenuActivity中初始化的是Activity级别的InformationViewModel,而OptionsFragment、TradingFragment中初始化的是Fragment级别的ViewModel,三者拿到的是完全不同的实例,请求得到的数据存在Fragment私有的ViewModel中,Fragment随横竖屏销毁时数据同步丢失。
  • 每次重建都新建Fragment实例:Activity横竖屏重建时,你没有判断savedInstanceState状态,每次都强制replace新的Fragment实例,原有Fragment的状态被完全覆盖。
  • ViewModel存储Fragment实例易引发内存泄漏:ViewModel生命周期长于Activity/Fragment,持有Fragment实例会导致销毁的Fragment无法被GC回收,存在内存溢出风险。

具体修改方案

1. 统一ViewModel作用域为Activity级别

所有场景下获取InformationViewModel时,都绑定到MenuActivity实例,保证整个页面生命周期内只有一个ViewModel实例,数据不会随Fragment销毁丢失:

  • OptionsFragment中ViewModel初始化代码修改为:
// 原代码:ViewModelProvider(this).get(InformationViewModel::class.java)
informationViewModel = ViewModelProvider(requireActivity()).get(InformationViewModel::class.java)
  • TradingFragment中ViewModel初始化代码同步修改为:
informationViewModel = ViewModelProvider(requireActivity()).get(InformationViewModel::class.java)

2. 调整Activity的Fragment挂载逻辑

删除InformationViewModel中存储Fragment实例的变量,新增currentPage字符串/枚举变量标记当前显示的页面类型,同时只有首次创建Activity时才主动挂载Fragment,横竖屏重建时由系统自动恢复已有Fragment:

// InformationViewModel中新增变量
var currentPage: String = "options" // 可选值options/personal/trading

修改MenuActivity的onCreate逻辑:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMenuBinding.inflate(layoutInflater)
    setContentView(binding.root)
    informationViewModel = ViewModelProvider(this).get(InformationViewModel::class.java)
    // 只有首次创建时才挂载Fragment,重建时系统自动恢复
    if (savedInstanceState == null) {
        val targetFragment = when(informationViewModel.currentPage) {
            "options" -> OptionsFragment()
            "personal" -> PersonalInfFragment()
            "trading" -> TradingFragment()
            else -> OptionsFragment()
        }
        showFragment(targetFragment)
    }
}

同时删除原来的onPassFragment回调逻辑,Fragment切换时直接修改ViewModel的currentPage标记即可。

3. TradingFragment的UI状态持久化

把TradingFragment中需要保留的参数(选择的时间范围、下拉框选中值)同步存储到ViewModel中,重建时读取ViewModel的值恢复UI:
首先在InformationViewModel中新增状态变量:

var tradingFrom: Int = 0
var tradingTo: Int = 0
var selectedCurrencyPair: String = ""
// 原有请求交易数据的LiveData保持不变即可

修改TradingFragment的相关逻辑:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // ... 原有控件初始化代码保持不变
    informationViewModel = ViewModelProvider(requireActivity()).get(InformationViewModel::class.java)

    // 恢复之前保存的时间选择状态
    from = informationViewModel.tradingFrom
    to = informationViewModel.tradingTo
    if (from != 0 && to != 0) {
        changeDateValueForText(from, to)
        rangeSeek.setValues(from.toFloat(), to.toFloat())
    } else {
        val cur_time = "${System.currentTimeMillis()}".substring(0, 10)
        rangeSeek.valueTo = Integer.valueOf(cur_time) * 1.0f
    }
    // 恢复下拉框选中状态
    if (informationViewModel.selectedCurrencyPair.isNotEmpty()) {
        val adapter = spinner.adapter
        for (i in 0 until adapter.count) {
            if (adapter.getItem(i).toString() == informationViewModel.selectedCurrencyPair) {
                spinner.setSelection(i)
                break
            }
        }
    }
    // ... 原有监听、RecyclerView初始化逻辑保持不变
    // LiveData observe后会自动收到ViewModel中保存的历史数据,直接刷新列表即可
}

private fun changeDateValueForText(start: Int, finish: Int) {
    from = start
    to = finish
    // 同步保存到ViewModel
    informationViewModel.tradingFrom = start
    informationViewModel.tradingTo = finish
    // ... 原有时间格式化逻辑保持不变
}

private fun startSearchingCurrencyTrading() {
    val pair = spinner.selectedItem.toString()
    // 同步保存选中的币种对
    informationViewModel.selectedCurrencyPair = pair
    informationViewModel.startRequestingCurrency(pair, from, to)
}

可选优化

如果需要避免每次切换Fragment都新建实例,可以在挂载Fragment前先通过supportFragmentManager.findFragmentByTag()查找已存在的Fragment实例,有就复用,没有再新建,能进一步提升切换性能。

内容的提问来源于stack exchange,提问作者Bekzhan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 21:27:01