Dagger Hilt:子Fragment/Dialog获取父ViewModel及@AssistedInject场景问题
在Dagger Hilt中让子Fragment/Dialog获取父Fragment的ViewModel(含@AssistedInject场景)
一、常规场景(父ViewModel无@AssistedInject)
如果父ViewModel是普通Hilt注入(仅标记@HiltViewModel),按以下方式处理即可:
前置要求
父Fragment、子Fragment/Dialog必须添加@AndroidEntryPoint注解,确保Hilt能处理ViewModel的注入逻辑。
正确代码实现
子Fragment/Dialog中使用viewModels()委托,指定父Fragment作为ViewModelStoreOwner:
@AndroidEntryPoint class ChildFragment : Fragment() { // 延迟到父Fragment已附加的生命周期阶段调用(如onViewCreated之后) private val parentViewModel: UserViewModel by viewModels({ requireParentFragment() }) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 在此安全使用parentViewModel } }
你崩溃的常见原因
- 缺少
@AndroidEntryPoint注解:父/子Fragment未添加该注解,导致Hilt无法提供正确的ViewModelFactory,触发注入失败。 - 过早调用
requireParentFragment():如果在onCreate等早期生命周期调用该方法,父Fragment可能还未完成附加,会抛出IllegalStateException。 - 父ViewModel未标记
@HiltViewModel:普通ViewModel未添加该注解,Hilt无法识别并完成注入。
二、@AssistedInject场景下的处理
当父ViewModel使用@AssistedInject(需要动态传入参数)时,默认的viewModels()委托无法适配,需通过自定义AssistedFactory+父Fragment暴露实例的方式处理:
步骤1:定义带AssistedInject的ViewModel及Factory
class UserViewModel @AssistedInject constructor( private val userRepo: UserRepository, @Assisted private val userId: String // 动态传入的参数 ) : ViewModel() { // 定义AssistedFactory,用于创建ViewModel实例 @AssistedFactory interface Factory { fun create(userId: String): UserViewModel } }
步骤2:父Fragment中创建并持有ViewModel
父Fragment通过hiltViewModel()委托传入Assisted参数,完成ViewModel实例化:
@AndroidEntryPoint class ParentFragment : Fragment() { // 传入动态参数创建ViewModel private val userViewModel: UserViewModel by hiltViewModel { factory -> factory.create("user_123") } // 暴露ViewModel给子Fragment的方法 fun getParentViewModel(): UserViewModel = userViewModel }
步骤3:子Fragment/Dialog获取父ViewModel
通过父Fragment的暴露方法,直接获取已创建的ViewModel实例:
@AndroidEntryPoint class ChildDialogFragment : DialogFragment() { private val parentViewModel: UserViewModel by lazy { // 强转父Fragment,确保类型匹配 (requireParentFragment() as ParentFragment).getParentViewModel() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 使用parentViewModel } }
替代方案:通过ViewModelProvider获取
如果不想直接依赖父Fragment的方法,也可以通过ViewModelProvider指定父Fragment的ViewModelStoreOwner获取实例(前提是父Fragment已完成ViewModel初始化):
private val parentViewModel: UserViewModel by lazy { val parentFragment = requireParentFragment() ViewModelProvider(parentFragment, parentFragment.defaultViewModelProviderFactory)[UserViewModel::class.java] }
内容的提问来源于stack exchange,提问作者Vivek Ojha
相关产品推荐
相关产品推荐

