如何用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时能复用各自的实例。
尝试过两种方法但都不符合需求:
- 使用
private val vm by hiltNavGraphViewModels(R.id.homeFragment):3个ChildFragment会共享同一个ViewModel实例。 - 直接通过
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
相关产品推荐
相关产品推荐

