代码之家  ›  专栏  ›  技术社区  ›  Dr.jacky Mateusz Kaflowski

如果没有@Provides注释方法,则无法提供该类

  •  2
  • Dr.jacky Mateusz Kaflowski  · 技术社区  · 6 年前

    我想注入一个依赖项( )变成我的碎片( 家庭碎片 ).

    HomeView模型 )在这个类中,我当然重写了父类的方法。

    HomeView模型 )是从 .

    这个 是正常的吗 open 视图模型 来自 安卓 生命周期组件。

    问题是我想注射的时候出错了 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)
    

    家庭碎片 :

    class HomeFragment : BaseFragment() {
    //Error comes from this line
    @Inject
    lateinit var viewModel: 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()
    }
    

    BaseView模型 :

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

    :

    @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
    }*/
    }
    

    视图模型键 :

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

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

    视图模型模块 :

    @Module
    internal abstract class ViewModelModule {
    
    @Binds
    internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
    }
    

    基本模块 :

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

    :

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

    我想要的就是 HomeView模型

    3 回复  |  直到 6 年前
        1
  •  2
  •   Gabe Sechan    6 年前

    如果您试图注入抽象基类的子类,则需要让dagger知道如何创建该实例。这是通过一个模块上的方法完成的,该模块返回该类型的实例,并具有@Provides注释。每次需要创建类的实例时,都会调用该类(如果您只需要一个实例,还可以使用@Singleton之类的范围注释对其进行注释)。

        2
  •  2
  •   Onik    6 年前

    都在这里。

    无法创建没有 @Inject constructor(...) . 另一方面 Java / 科特林 不能创建抽象类和 “使用” Java 科特林

    你可以选择延长 HomeViewModel 并将 匕首 HomeView模型 不是抽象的。

        3
  •  2
  •   Onik    6 年前

    HomeView模型 &这个 :

    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 :

    class HomeViewModelImpl : HomeViewModel.Implementation() {
    
        override fun fetchAlbums() { }
    }
    

    家庭碎片

    class HomeFragment : BaseFragment() {
    
        @Inject
        lateinit var viewModel: HomeViewModel
    }
    

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