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

Android Jetpack Compose底部导航+Hilt ViewModel内存泄漏问题

解决底部导航切换时ViewModel不销毁的问题

问题原因

默认使用navController.navigate()切换底部导航页面时,新页面会被添加到返回栈中,前一个页面仅进入ON_STOP状态而非ON_DESTROY,导致绑定的ViewModel无法触发onCleared(),多次切换后会产生多个ViewModel实例引发内存泄漏。

解决方案

修改导航逻辑,通过popUpTo和launchSingleTop参数控制返回栈行为,确保切换底部导航时清理前一个页面的实例:

1. 调整底部导航的导航代码

CustomBottomNavigation(
    //...
    onSelectionChanged = {
        val destination = when (it) {
            0 -> "screen1"
            1 -> "screen2"
        }
        navController.navigate(destination) {
            // 弹出返回栈到起始页,同时保存页面状态
            popUpTo(navController.graph.startDestinationId) {
                saveState = true
            }
            // 确保目标页面不会重复创建实例
            launchSingleTop = true
            // 恢复之前保存的页面状态
            restoreState = true
        }
    }
)

参数说明

  • popUpTo(startDestinationId):将返回栈中除起始页之外的所有页面弹出,保证返回栈的简洁性;saveState=true会保存被弹出页面的状态,下次切换回来时可恢复。
  • launchSingleTop=true:如果目标页面已经在返回栈顶部,不会重新创建新实例,避免重复初始化。
  • restoreState=true:自动恢复之前保存的页面状态,提升切换时的用户体验。

2. 验证ViewModel销毁状态

在ViewModel中重写onCleared()方法,确认页面销毁时ViewModel是否被正确清理:

@HiltViewModel
class Screen2ViewModel @Inject constructor(
    //...
) : ViewModel() {
    //...
    override fun onCleared() {
        super.onCleared()
        println("Screen2ViewModel 已被销毁")
    }
}

当切换回Screen1时,Screen2会触发ON_DESTROY,同时ViewModel的onCleared()会被调用,日志输出对应内容,说明实例已被正确回收。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 09:32:42