简体   繁体   English

没有@Provides注释的方法,无法提供该类

[英]The class cannot be provided without an @Provides-annotated method

I want to inject a dependency ( HomeViewModel ) into my fragment ( HomeFragment ). 我想将依赖项( HomeViewModel )注入片段( HomeFragment )中。

I have a class ( HomeViewModelImpl ) which implemented that abstraction ( HomeViewModel ) and inside this class, I'm overriding parent's methods of course. 我有一个类(HomeViewModelImpl),它实施了抽象(HomeViewModel)和本类中,我重写当然父母的方法。

The abstraction class ( HomeViewModel ) is an abstract class which extended from BaseViewModel . 抽象类( HomeViewModel )是从BaseViewModel扩展的抽象类。

The BaseViewModel is a normal open class in which extended from ViewModel class from the Android lifecycle component. BaseViewModel是一个普通的open类,其中从Android生命周期组件的ViewModel类进行了扩展。

The problem is I got an error when I want to inject HomeViewModel into the fragment: 问题是当我要将HomeViewModel注入片段时出现错误:

> error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] com.example.mvvm.ui.home.HomeViewModel cannot be provided without an @Provides-annotated method.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.example.mvvm.MyApplication> {
            ^
  com.example.mvvm.ui.home.HomeViewModel is injected at
      com.example.mvvm.ui.home.HomeFragment.viewModel
  com.example.mvvm.ui.home.HomeFragment is injected at
      dagger.android.AndroidInjector.inject(T)

HomeFragment : HomeFragment

class HomeFragment : BaseFragment() {
//Error comes from this line
@Inject
lateinit var viewModel: HomeViewModel
}

HomeViewModel : HomeViewModel

//If I write @Inject annotation here, the error goes away,
//but then I have to remove the abstract keyword, then I have to open the class
//and the useful usage of that abstract class in HomeViewModelImpl class
//will be gone, and I have to set open keyword on the HomeViewModel and
//on its method.
/*open*/ abstract class HomeViewModel /*@Inject constructor()*/ : BaseViewModel() {

sealed class State {
    data class AlbumsLoaded(val albums: List<AlbumData>) : State()
    object ShowLoading : State()
    object ShowContent : State()
    object ShowError : State()
}

abstract fun fetchAlbums()
}

BaseViewModel : BaseViewModel

open class BaseViewModel : ViewModel() {

private val compositeDisposable: CompositeDisposable = CompositeDisposable()

protected fun addDisposable(disposable: Disposable) {
    compositeDisposable.add(disposable)
}

private fun clearDisposables() {
    compositeDisposable.clear()
}

override fun onCleared() {
    clearDisposables()
}
}

HomeModule : HomeModule

@Module(includes = [
//HomeModule.HomeViewModelProvide::class,
HomeModule.HomeVM::class])
internal abstract class HomeModule {

@ContributesAndroidInjector
internal abstract fun homeFragment(): HomeFragment

@Module
abstract class HomeVM {
    @Binds
    @IntoMap
    @ViewModelKey(HomeViewModelImpl::class)
    internal abstract fun bindHomeViewModel(viewModel: HomeViewModelImpl): HomeViewModel
//I've changed the return type of this method from HomeViewModel to
//BaseViewModel and ViewModel, but error still exists!
}

//I've written this to provide HomeViewModel, but compiler shows another error
//that says there is a dependency circle!
/*@Module
class HomeViewModelProvide {
    @Provides
    internal fun provideHomeViewModel(homeViewModel: HomeViewModel): HomeViewModel = homeViewModel
}*/
}

ViewModelKey : ViewModelKey

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

ViewModelFactory : ViewModelFactory

class ViewModelFactory @Inject constructor(
    private val creators: @JvmSuppressWildcards Map<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {

override fun <T : ViewModel> create(modelClass: Class<T>): T {
    var creator: Provider<out ViewModel>? = creators[modelClass]
    if (creator == null) {
        for ((key, value) in creators) {
            if (modelClass.isAssignableFrom(key)) {
                creator = value
                break
            }
        }
    }
    if (creator == null) {
        throw IllegalArgumentException("unknown model class $modelClass")
    }
    try {
        @Suppress("UNCHECKED_CAST")
        return creator.get() as T
    } catch (e: Exception) {
        throw RuntimeException(e)
    }
}
}

ViewModelModule : ViewModelModule

@Module
internal abstract class ViewModelModule {

@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}

BaseModule : BaseModule

@Module
internal abstract class BaseModule {

@ContributesAndroidInjector(modules = [HomeModule::class])
internal abstract fun mainActivity(): MainActivity
}

AppComponent : AppComponent

@Singleton
@Component(modules = [
AndroidSupportInjectionModule::class,
ViewModelModule::class,
AppModule::class,
BaseModule::class
])
interface AppComponent : AndroidInjector<MyApplication> {
@Component.Builder
abstract class Builder : AndroidInjector.Builder<MyApplication>()
}

Note: Please read inline comments on above snippet codes. 注意:请阅读上述代码段的内联注释。

All I want is set HomeViewModel as an abstract class and inject it where I want. 我想要的只是将HomeViewModel设置为抽象类,然后将其注入到我想要的位置。

If you're trying to inject a child of an abstract base class, you need to let dagger know how to create that instance. 如果要注入抽象基类的子级,则需要让d​​agger知道如何创建该实例。 That's done via a method on a module that returns an instance of the type and has an @Provides annotation. 这是通过模块上的方法完成的,该方法返回该类型的实例并具有@Provides批注。 That class will be called every time it needs to create an instance of the class (if you only wish 1 instance of it, you can also annotate it with a scope annotation like @Singleton). 每当需要创建该类的实例时,都会调用该类(如果您只希望一个实例,则还可以使用@Singleton之类的作用域注释对其进行注释)。

The reason this is necessary is because the class you're trying to make is abstract. 之所以需要这样做,是因为您要创建的类是抽象的。 It can't be instantiated directly, so Dagger can't do its normal thing of calling the @Inject constructor or default constructor. 它不能直接实例化,因此Dagger无法完成其正常工作,即调用@Inject构造函数或默认构造函数。

The solution is to create a middle abstract class between the child and the real parent, then the child has to extend from that middle abstract class. 解决方案是在子级和真正的父级之间创建一个中间抽象类,然后该子类必须从该中间抽象类扩展。

HomeViewModel & the Middle Abstract class : HomeViewModel中间抽象类

open class HomeViewModel @Inject constructor() : BaseViewModel() {

    sealed class State {
        data class AlbumsLoaded(val albums: List<AlbumData>) : State()
        object ShowLoading : State()
        object ShowContent : State()
        object ShowError : State()
    }

    abstract class Implementation : HomeViewModel() {
        abstract fun fetchAlbums()
    }
}

HomeViewModelImpl : HomeViewModelImpl

class HomeViewModelImpl : HomeViewModel.Implementation() {

    override fun fetchAlbums() { }
}

HomeFragment : HomeFragment

class HomeFragment : BaseFragment() {

    @Inject
    lateinit var viewModel: HomeViewModel
}

Source: https://stackoverflow.com/a/18331547/421467 资料来源: https : //stackoverflow.com/a/18331547/421467

It's all here. 都在这里

Dagger cannot create an instance of class without @Inject constructor(...) . 没有@Inject constructor(...) Dagger无法创建类的实例。 On the other hand in Java / Kotlin you cannot create an instance of abstract class and Dagger "uses" Java / Kotlin in this case. 另一方面,在Java / Kotlin中,您无法创建抽象类的实例,在这种情况下, Dagger会 “使用” Java / Kotlin

An option you have is to extend HomeViewModel and inject the child instance with Dagger or make HomeViewModel not abstract. 您可以选择扩展HomeViewModel并使用Dagger注入子实例,或者使HomeViewModel不是抽象的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 没有@Provides注释的方法无法提供 - Cannot be Provided Without an @Provides-annotated Method 如果没有@Provides 注释的方法 Dagger/MissingBinding,则无法提供 - cannot be provided without an @Provides-annotated method Dagger/MissingBinding 没有@Annex-annotated方法就无法提供上下文,但它是? - Context cannot be provided without an @Provides-annotated method, but it is? Android匕首2:如果没有@Provides注释的方法,则无法提供依赖项 - Android dagger 2: dependency cannot be provided without an @Provides-annotated method 不能在没有 @Provides 注释的方法的情况下提供(Android Kotlin 中的 Dagger 2) - Cannot be provided without an @Provides-annotated method (Dagger 2 in Android Kotlin) Dagger 2错误:依赖项“如果没有@Provides注释的方法就无法提供” - Dagger 2 error: dependency “cannot be provided without an @Provides-annotated method" 错误:如果没有 @Provides-annotated 方法就无法提供 - Error: cannot be provided without an @Provides-annotated method 匕首柄:如果没有@Provides-annotated 方法,则无法提供 - Dagger Hilt: cannot be provided without an @Provides-annotated method Dagger2:如果没有 @Provides 注释的方法,就无法提供 ViewModel - Dagger2: ViewModel cannot be provided without an @Provides-annotated method kotlin + Dagger2:如果没有@ Provide-annotated方法,则无法提供 - kotlin + Dagger2 : cannot be provided without an @Provides-annotated method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM