Android导航图作用域下跨多子图共享Fragment的ViewModel最佳处理方案
最佳解决方案
针对Fragment被多子图调用、需绑定对应子图作用域ViewModel且避免硬编码导航图ID的场景,可按适用场景选择以下方案:
- 方案1:自定义动态获取当前父导航图ID的ViewModel委托
该方案保留导航图作用域绑定的特性,完全消除硬编码ID。首先为Fragment定义扩展委托:
调用时直接使用该委托即可,无需传入固定ID:import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navGraphViewModels inline fun <reified VM : ViewModel> Fragment.parentGraphViewModels(): Lazy<VM> { val currentDest = findNavController().currentDestination ?: error("Current destination not found") // 自动获取当前Fragment所属的父导航图ID val parentGraphId = currentDest.parent.id return navGraphViewModels(parentGraphId) }private val fvm: SoftenerViewModel by parentGraphViewModels() - 方案2:绑定父Fragment作用域的ViewModel
如果该复用Fragment始终作为某类父Fragment的子节点存在,优先使用父Fragment的ViewModel作用域,完全和导航逻辑解耦,调用方式如下:
此时ViewModel生命周期和父Fragment完全同步,不受导航图ID变更影响。private val fvm: SoftenerViewModel by viewModels({ requireParentFragment() }) - 方案3:通过上一级回退栈获取ViewModel
如果需要更灵活的作用域控制,也可以直接通过上一级导航回退栈获取ViewModel实例:private val fvm: SoftenerViewModel by lazy { val navController = findNavController() val parentBackEntry = navController.previousBackStackEntry ?: error("No parent navigation back stack entry") ViewModelProvider(parentBackEntry)[SoftenerViewModel::class.java] }
注意:如果多个子图对应的ViewModel需要不同的实现,可配合导航图的
<argument>标签传递ViewModel的Class类型,在复用Fragment中动态解析获取即可。
内容的提问来源于stack exchange,提问作者Mike Hanafey
相关产品推荐
相关产品推荐

