当前位置: 首页 > 知识库问答 >
问题:

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

车子平
2023-03-14

我想在我的片段(HomeFragment)中注入一个依赖项(HomeViewModel)。

我有一个类(HomeViewModelImpl)实现了该抽象(HomeViewModel),在这个类中,我当然覆盖了父级的方法。

抽象类(HomeViewModel)是从BaseViewModel扩展而来的抽象类。

BaseViewModel是一个普通的开放类,它从Android生命周期组件的ViewModel类扩展而来。

问题是当我想将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()
}

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

主页模块:

@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:

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

视图模型工厂:

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
}

AppComponent:

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

我想要的只是将HomeViewModel设置为抽象类并将其注入我想要的地方。

共有3个答案

马欣德
2023-03-14

都在这里了。

Dagger不能在没有@Inject构造函数(...)的情况下创建类的实例。另一方面,在Java/静态编程语言中,您不能创建抽象类的实例,在这种情况下Dagger“使用”Java/静态编程语言。

您可以选择扩展HomeViewModel,并使用Dagger注入子实例,或者使家庭视图模型不抽象。

段兴为
2023-03-14

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

这是必要的原因是,你试图做的类是抽象的。它不能直接实例化,因此Dagger无法执行其正常的事情,即调用@Inject构造函数或默认构造函数。

冀弘厚
2023-03-14

解决方案是在子级和实际父级之间创建一个中间抽象类,然后子级必须从该中间抽象类扩展。

首页视图模型

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

 类似资料:
  • 我是新来的,用匕首。所以,我不能解决这个有什么问题。我只想问在这里解决它。 这是错误: c:\ Users \ MSI \ Documents \ MyAndroidProjects \ movie projects \ App \ build \ generated \ hilt \ component _ sources \ debug \ com \ example \ movie App

  • 问题内容: 我正在尝试在我的项目中实现dagger2,但遇到错误“ android.app.Application必须在没有@Inject构造函数或@Provides注释方法的情况下才能提供 ”。 这是我的代码: App.java di / AppModule.java di / AppComponent.java di / TestClassModule.java di / TestClassC

  • 我正试图从这篇中级文章中学习Dagger2,并将RequestQueue作为活动级依赖项传递:https://proandroiddev.com/dagger-2-annotations-binds-contributesandroidinjector-a09e6a57758f我可以很好地创建应用程序组件,但我在ContributesAndroidInjector方面遇到了很多麻烦。应用类别: 应

  • 所以我正在尝试将我的整个应用程序从匕首迁移到刀柄,显然我无法注入活动和碎片。 我的活动: 我的片段: 我的应用程序类: 像这样注入我的活动: 它抛出了这个错误: 项目级成绩: 应用级 Gradle(所有 3 个模块): 会不会是我的活动和片段扩展了不能用@ AndroidEntryPoint注释的基,因为它们有类型参数??救命啊! 同样在 dagger2 中,我使用了如下接口: 它的工作,但柄据说

  • 我试图在learn pourposes的种子项目中添加dagger2(我不是专家),但我有同样的问题: E: /Users/foca/projects/personalProjects/bar-droid-application/bar-droid/app/build/tmp/kapt3/stubs/debug/com/bar/bar_droid/di/AppC: 8:错误:[Dagger/Mis

  • 问题内容: 我正在做一个很大的项目,有很多注入。当前,我们正在使用一个类,该类为需要一次的每次注入实现,并且它们大多具有一个行方法。 每当我需要一个新的提供程序时,创建一个新的类就变得很烦人。使用提供程序类比使用方法有什么好处,反之亦然? 问题答案: 据我所知,它们在大多数简单情况下是完全等效的。 无论哪种样式,即使键绑定到类或实例,Guice都可以让您注入和。如果直接获取实例,Guice会自动调