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
相关产品推荐
相关产品推荐

