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

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
    }
}

你崩溃的常见原因

  1. 缺少@AndroidEntryPoint注解:父/子Fragment未添加该注解,导致Hilt无法提供正确的ViewModelFactory,触发注入失败。
  2. 过早调用requireParentFragment():如果在onCreate等早期生命周期调用该方法,父Fragment可能还未完成附加,会抛出IllegalStateException。
  3. 父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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 00:15:22