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

如何用Hilt为ViewPager中父Fragment作用域的子Fragment创建不同ViewModel实例

问题场景

我有一个属于应用导航图的HomeFragment,其内部的ViewPager包含3个同一类ChildFragment的实例。每个ChildFragment都需要一个ChildViewModel实例,ViewModel定义如下:

@HiltViewModel
class ChildViewModel @Inject constructor(
    private val repo: Repository
) : ViewModel() {

}

希望创建作用域为HomeFragment导航目标生命周期的不同ChildViewModel实例,要求每个子Fragment拥有独立的ViewModel,且用户返回HomeFragment时能复用各自的实例。

尝试过两种方法但都不符合需求:

  1. 使用private val vm by hiltNavGraphViewModels(R.id.homeFragment):3个ChildFragment会共享同一个ViewModel实例。
  2. 直接通过ViewModelProvider(it).get(args.sectionId, ChildViewModel::class.java)初始化:抛出无法创建ViewModel实例的异常,因为未使用Hilt的ViewModel工厂。
解决方案

要实现需求,需要结合Hilt的ViewModel工厂,以HomeFragment作为ViewModelStore宿主,并为每个ChildViewModel指定唯一的存储key(比如子Fragment的sectionId),这样既能保证ViewModel作用域绑定HomeFragment的生命周期,又能让每个子Fragment获得独立实例。

具体实现代码

方式1:使用lazy委托初始化(推荐)

在ChildFragment中添加以下代码:

private val vm: ChildViewModel by lazy {
    // 获取父Fragment(HomeFragment)作为ViewModelStore的宿主
    val homeFragment = requireParentFragment() as HomeFragment
    // 用Hilt提供的工厂,结合唯一key(sectionId)创建/获取ViewModel
    ViewModelProvider(
        homeFragment,
        homeFragment.defaultViewModelProviderFactory
    ).get(args.sectionId.toString(), ChildViewModel::class.java)
}

方式2:在onCreateView中初始化

private lateinit var vm: ChildViewModel

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    super.onCreateView(inflater, container, savedInstanceState)
    val homeFragment = requireParentFragment() as HomeFragment
    vm = ViewModelProvider(
        homeFragment,
        homeFragment.defaultViewModelProviderFactory
    ).get(args.sectionId.toString(), ChildViewModel::class.java)
    
    // 后续视图初始化逻辑
    return inflater.inflate(R.layout.fragment_child, container, false)
}

关键说明

  • ViewModelStore宿主选择:指定HomeFragment作为ViewModel的存储宿主,确保ViewModel的生命周期与HomeFragment绑定,用户返回HomeFragment时实例不会被销毁。
  • 自定义存储key:用每个ChildFragment独有的sectionId作为key,让ViewModelStore能区分不同的ChildViewModel实例,避免共享。
  • Hilt工厂的使用:通过homeFragment.defaultViewModelProviderFactory获取Hilt注入的ViewModel工厂,解决直接使用ViewModelProvider无法创建@HiltViewModel注解实例的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 06:20:05