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

求助:NavigationController与BottomNavigation下Fragment中LiveData状态丢失问题

问题原因分析
  • NavigationController默认销毁策略:底部导航切换时,当前Fragment会被销毁而非隐藏,绑定Fragment生命周期的ViewModel也会随之销毁重建,导致数据丢失。
  • ViewModel初始化错误:若在Fragment内通过ViewModelProvider(this)获取ViewModel,Fragment重建时会生成新的ViewModel实例,原有数据无法保留。
  • 配置变更未处理:屏幕旋转等配置变更触发Fragment重建时,若ViewModel未绑定正确的生命周期或未使用状态保存机制,数据会丢失。
可行解决方案

方案1:绑定Activity生命周期的ViewModel

通过获取Activity级别的ViewModel,让数据生命周期与Activity绑定,不受Fragment销毁重建影响。适合需要在多个底部Fragment共享数据的场景。

// Fragment中获取Activity级ViewModel
private val sharedViewModel: MyViewModel by viewModels(
    ownerProducer = { requireActivity() }
)

方案2:自定义FragmentNavigator实现Fragment hide/show切换

修改NavigationController的默认行为,让底部导航切换时仅隐藏/显示Fragment,而非销毁重建,保留Fragment及ViewModel的完整状态。

自定义Navigator

class KeepAliveFragmentNavigator(
    context: Context,
    manager: FragmentManager,
    containerId: Int
) : FragmentNavigator(context, manager, containerId) {

    override fun navigate(
        destination: Destination,
        args: Bundle?,
        navOptions: NavOptions?,
        navigatorExtras: Navigator.Extras?
    ): NavDestination? {
        val tag = destination.id.toString()
        val transaction = manager.beginTransaction()

        // 复用已存在的Fragment
        var fragment = manager.findFragmentByTag(tag)
        if (fragment != null) {
            transaction.show(fragment)
        } else {
            fragment = destination.createFragment(args)
            transaction.add(containerId, fragment, tag)
        }

        // 隐藏其他底部导航Fragment
        manager.fragments.forEach {
            if (it.tag != tag && manager.fragments.contains(it)) {
                transaction.hide(it)
            }
        }

        transaction.setReorderingAllowed(true)
        transaction.commit()
        return destination
    }
}

在Activity中注册自定义Navigator

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    
    // 添加自定义Navigator
    val navigator = KeepAliveFragmentNavigator(this, supportFragmentManager, R.id.nav_host_fragment)
    navController.navigatorProvider.addNavigator(navigator)
    
    // 设置导航图
    navController.setGraph(R.navigation.nav_graph)
}

方案3:使用SavedStateHandle保存ViewModel数据

通过SavedStateHandle持久化ViewModel中的关键数据,即使ViewModel因配置变更或销毁重建,也能恢复数据。适合不需要跨Fragment共享,但需在配置变更时保留的数据。

ViewModel中使用SavedStateHandle

class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    // 直接从SavedStateHandle获取LiveData
    private val _userData = savedStateHandle.getLiveData<String>("user_key")
    val userData: LiveData<String> = _userData

    fun updateUserData(data: String) {
        _userData.value = data
        // 同步保存到SavedStateHandle
        savedStateHandle.set("user_key", data)
    }
}

Fragment中初始化ViewModel

private val viewModel: MyViewModel by viewModels {
    SavedStateViewModelFactory(requireActivity().application, this)
}

内容的提问来源于stack exchange,提问作者Khalid Ahmad Fazli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 10:12:54