我有一个片段
HomeFragment
,它是应用程序导航图的一部分。在 FragmentHome
中,我有一个 viewpager,其中包含 3 个同一类 ChildFragment
的片段实例。每个 ChildFragment
都需要一个 ChildViewModel
的实例,定义如下
@HiltViewModel
class ChildViewModel @Inject constructor(
private val repo: Repository
) : ViewModel() {
}
如何创建视图模型
ChildViewModel
的不同实例,其范围仅限于 HomeFragment
导航目的地的生命周期?
我尝试了以下行。但这在所有 3 个
ChildFragments
中共享相同的视图模型实例,这是不希望的。
private val vm by hiltNavGraphViewModels(R.id.homeFragment)
据我了解,ViewModelStore 使用一个 Key,它是视图模型的规范名称来保存它。有没有办法可以为每个片段使用自定义键,以便每个
ChildFragment
都有自己的实例?
我也尝试过
private lateinit var vm: ChildViewModel
...
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
super.onCreateView(inflater, container, savedInstanceState)
parentFragment?.let {
vm = ViewModelProvider(it).get(args.sectionId, CihldViewModel::class.java)
}
}
但这引发了一些异常,因为它无法创建我的 ViewModel 实例。我对使用 Viewmodel Factory 方法有点不熟悉,因为 Hitl 为我们处理了它。
我想将此视图模型范围限制到
HomeFragment
导航目标的原因是为了保存状态,这样当用户重新登陆 HomeFragment
时,我可以为每个子片段重用相同的视图模型实例
所以,经过大量的挖掘和阅读,我终于弄清楚了,好吧。最初我希望使用 CreationExtras 或 Hilt AssistedInject 来实现这一目标。但不幸的是,这些都不起作用。
原因是,为了使自定义键起作用,我们必须将该自定义键传递给
ViewModelProvider.get()
并且以下委托都不会向其传递字符串键。因此,将创建一个 ViewModel 实例并使用默认键保存。
by viewModels()
by activityViewModels()
by navGraphViewModels()
by hiltNavGraphViewModels()
令人惊讶的是,这可以通过
hiltViewModel(viewModelStoreOwner: ViewModelStoreOwner, key: String?)
在 Compose 中实现,但同样不适用于 Fragment。
无论如何,这是对我有用的解决方案。如果您深入研究
by hiltNavGraphViewModels()
,您会发现它只是创建一个具有默认参数值的 ViewModelProvider,但 HiltViewModelFactory
除外,它负责将依赖项注入到我们的 HiltViewModel
带注释的 ViewModel 中。因此,我只需创建一个具有相同默认值的 ViewModelProvider 并根据需要传递我的自定义密钥。
private lateinit var vm: ChildViewModel
...
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
super.onCreateView(inflater, container, savedInstanceState)
parentFragment?.let { it ->
val backStackEntry = it.findNavController().getBackStackEntry(R.id.homeFragment)
vm = ViewModelProvider(
it,
HiltViewModelFactory(
requireActivity(),
backStackEntry.defaultViewModelProviderFactory
)
)[args.sectionId, ChildViewModel::class.java]
}
}
参考资料: