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

Dagger注入ViewModel失败:MissingBinding错误求助

解决Dagger注入ViewModel时的MissingBinding错误

问题描述

注入CountriesViewModel时持续报错,即便已给ViewModel添加@Inject构造函数,仍收到以下提示:

error: [Dagger/MissingBinding] com.example.excitelassignment.countrylist.presentation.viewmodel.CountriesViewModel cannot be provided without an @Inject constructor or an @Provides-annotated method.
中文翻译:[Dagger/缺失绑定] 无法提供com.example.excitelassignment.countrylist.presentation.viewmodel.CountriesViewModel,需添加@Inject构造函数或@Provides注解方法。

相关代码

ApplicationComponent

@Singleton
@Component(modules = [AndroidInjectionModule::class, ActivityBuilderModule::class, FragmentBuilderModule::class, BaseNetworkModule::class, CountriesListApiModule::class])
interface ApplicationComponent : AndroidInjector<ExcitelApplication> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder

        @BindsInstance
        fun bindContext(context: Context): Builder

        fun build(): ApplicationComponent
    }
}

CountriesListFragment

class CountriesListFragment : Fragment(R.layout.countries_fragment) {
    @Inject
    lateinit var viewModelFactory: ExcitelViewModelFactory<CountriesViewModel>
    lateinit var countriesViewModel: CountriesViewModel

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        countriesViewModel = ViewModelProvider(this, viewModelFactory)[CountriesViewModel::class.java]
        countriesViewModel.getCountries()
    }
}

ExcitelApplication

class ExcitelApplication : DaggerApplication() {
    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return DaggerApplicationComponent.builder().application(this).bindContext(this).build()
    }
}

CountryListActivity

class CountryListActivity: BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState)
        setContentView(R.layout.countries_activity)
        replaceFragment(CountriesListFragment())
    }

    open fun replaceFragment(fragment: Fragment) {
        val fragmentManager: FragmentManager = supportFragmentManager
        val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
        fragmentTransaction.add(R.id.container, fragment)
        fragmentTransaction.addToBackStack(fragment.toString())
        fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
        fragmentTransaction.commit()
    }
}

CountriesViewModel

class CountriesViewModel @Inject constructor(
    private val countriesUseCase: CountriesUseCaseImpl
) : ViewModel() {
    val countriesLiveData = MutableLiveData<Resource<CountriesResult>>()
    private val compositeDisposable = CompositeDisposable()

    fun getCountries() {
        val countriesDisposable = countriesUseCase.getCountries()
            .doOnSubscribe {
                countriesLiveData.value = Resource.Loading()
            }
            .subscribe(
                { success ->
                    countriesLiveData.postValue(Resource.Success(success))
                },
                { throwable ->
                    countriesLiveData.postValue(Resource.Failure(throwable))
                }
            )
        compositeDisposable.add(countriesDisposable)
    }

    override fun onCleared() {
        super.onCleared()
        compositeDisposable.clear()
    }
}

ExcitelViewModelFactory

class ExcitelViewModelFactory @Inject constructor(private val viewModel: Lazy<CountriesViewModel>) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T = viewModel.get() as T
}

解决方案

  • 检查CountriesUseCaseImpl的依赖配置:ViewModel构造依赖该类,必须确保它要么有@Inject注解的构造函数,要么在某个Dagger模块中通过@Provides方法提供实例。若该依赖无法被Dagger创建,会间接导致ViewModel无法注入,触发MissingBinding错误。
  • 验证FragmentBuilderModule的配置:确保模块中用@ContributesAndroidInjector注解CountriesListFragment,让Dagger知晓如何注入该Fragment。示例配置:
    @Module
    abstract class FragmentBuilderModule {
        @ContributesAndroidInjector
        abstract fun contributeCountriesListFragment(): CountriesListFragment
    }
    
  • 优化ViewModelFactory为通用实现:当前Factory硬编码针对CountriesViewModel,改成通用版本可避免泛型识别问题,示例:
    class ExcitelViewModelFactory @Inject constructor(
        private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
    ) : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            val creator = creators[modelClass] ?: creators.entries.firstOrNull {
                modelClass.isAssignableFrom(it.key)
            }?.value ?: throw IllegalArgumentException("Unknown model class $modelClass")
            try {
                @Suppress("UNCHECKED_CAST")
                return creator.get() as T
            } catch (e: Exception) {
                throw RuntimeException(e)
            }
        }
    }
    
  • 清理重建项目:Dagger注解处理器缓存可能引发异常,执行Android Studio中的Clean Project和Rebuild Project操作,重新生成Dagger注入代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 05:05:21