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

如何通过Dagger2注入ViewModel Factory 解决Fragment初始化崩溃问题

错误根因

出现kotlin.UninitializedPropertyAccessException: lateinit property factory has not been initialized崩溃的核心原因如下:

  1. by viewModels传入的工厂lambda会在首次访问signupViewModel实例时执行,如果代码在onAttach方法执行完成(Dagger完成注入)前就访问了signupViewModel,就会调用还未初始化的factory
  2. Dagger Component配置错误:你的AppComponent没有声明针对SignupFragment的注入方法,或者注入方法的参数是通用Fragment类型而非具体SignupFragment类型,导致inject(this)执行后factory没有被正确赋值

修复方案

方案一:修正注入配置 + 调整ViewModel访问时机

  • 确认AppComponent中已声明对应子类的注入方法:
@Singleton
@Component
interface AppComponent {
    // 必须是具体的SignupFragment类型,不能用父类Fragment
    fun inject(fragment: SignupFragment)
}
  • 不要在Fragment的init代码块、属性初始化阶段访问signupViewModel,所有ViewModel的调用逻辑放到onViewCreated及之后的生命周期节点执行

方案二:改用自定义懒加载ViewModel(适配所有场景)

如果无法避免提前访问ViewModel的场景,替换by viewModels属性委托为自定义懒加载实现,确保factory注入完成后才会初始化ViewModel:

class SignupFragment : Fragment(R.layout.signup_page) {

    private val binding by viewBinding(SignupPageBinding::bind)

    @Inject
    lateinit var factory: SignupViewModel.Factory

    // 自定义懒加载,首次访问时才创建ViewModel,此时factory已完成注入
    private val signupViewModel: SignupViewModel by lazy {
        ViewModelProvider(this, factory)[SignupViewModel::class.java]
    }

    override fun onAttach(context: Context) {
        context.appComponent.inject(this)
        super.onAttach(context)
    }
}

方案三:迁移到Hilt(可选,简化注入逻辑)

如果项目允许迁移到Google官方的Hilt依赖注入框架,可完全规避Factory注入的顺序问题:

  1. 给ViewModel添加@HiltViewModel注解,删除自定义Factory类
@HiltViewModel
class SignupViewModel @Inject constructor(private val service: AuthService) : ViewModel() {
    private var email: String = ""
    private var password: String = ""
    private val _uiState = MutableStateFlow<SignupState>(SignupState.Success(null))
    val uiState: StateFlow<SignupState> = _uiState
}
  1. 给Fragment添加@AndroidEntryPoint注解,直接用无参的by viewModels获取实例
@AndroidEntryPoint
class SignupFragment : Fragment(R.layout.signup_page) {
    private val binding by viewBinding(SignupPageBinding::bind)
    private val signupViewModel: SignupViewModel by viewModels()
    // 无需手动注入Factory,也不需要在onAttach中调用inject方法
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 11:27:03