简体   繁体   中英

dagger error binding with matching key exists in component

Dagger 2

/di/AppComponent.java:19: error: [Dagger/MissingBinding] ProductListFragment cannot be provided without an @Inject constructor or an @Provides-annotated method. This type supports members injection but cannot be implicitly provided.
public abstract interface AppComponent {
                ^
  A binding with matching key exists in component: MainFragmentProvider_BindProductListFragment.ProductListFragmentSubcomponent
      ProductListFragment is injected at
          productlist.ProductListModule.provideChildFragmentManager(productListFragment)
      androidx.fragment.app.FragmentManager is injected at
          productlist.adapter.NewProductListPagerAdapter(…, fragmentManager)
      productlist.adapter.NewProductListPagerAdapter is injected at
          productlist.ProductListV2Fragment.mPagerAdapter
      productlist.ProductListV2Fragment is injected at
          dagger.android.AndroidInjector.inject(T) [di.AppComponent → di.BuilderModule_BindMainActivity.MainActivitySubcomponent →  MainFragmentProvider_BindProductListV2Fragment.ProductListV2FragmentSubcomponent]

I have the following module with these 2 fragments here:

@Module
abstract class FragmentProvider {
    @PerFragment
    @ContributesAndroidInjector(modules = [ProductListModule::class])
    abstract fun bindProductListV2Fragment(): ProductListV2Fragment
    
    @PerFragment
    @ContributesAndroidInjector(modules = [ProductListModule::class])
    abstract fun bindProductListFragment(): ProductListFragment
}

In my ProductListModule I have the following:

@Module
class ProductListModule {

    @Provides
    fun provideChildFragmentManager(productListFragment: ProductListFragment) =
        productListFragment.childFragmentManager
}

The fragmentManager will be injected into the following class:

class NewProductListPagerAdapter @Inject constructor(
    @ActivityContext private val context: Context,
    fragmentManager: FragmentManager
) { ..... }

And both fragments will inject this NewProductListPagerAdapter in them.

class ProductListV2Fragment  : BaseProductListFragment() {

    @Inject
    lateinit var mPagerAdapter: NewProductListPagerAdapter
}

class ProductListFragment  : BaseProductListFragment() {

    @Inject
    lateinit var mPagerAdapter: NewProductListPagerAdapter
}

My AppComponent:

@Singleton
@Component(
    modules = [
        AndroidSupportInjectionModule::class,
        AppModule::class,
        ProductModule::class,
        BaseAppModule::class
    ]
)
interface AppComponent {
    @Component.Factory
    interface Factory {
        fun create(
            @BindsInstance application: Application,
        ): AppComponent
    }

    fun inject(tsApplication: TsApplication)
}

Your module depends on ProductListFragment to obtain a child FragmentManager . However, that same module is used to inject into ProductListV2Fragment , and there is no ProductListFragment available at that point.

In order to reuse that module, you will need to split the dependency on ProductListFragment into a separate module. This module should be used for ProductListFragment , and a similar module should be used for ProductListV2Fragment . In these modules, you can either provide FragmentManager directly or bind both fragments to a common superclass such as Fragment or BaseProductListFragment .

If you bind both fragments to Fragment , the resulting code will look like this:

@Module
abstract class FragmentProvider {
    @PerFragment
    @ContributesAndroidInjector(modules = [
        ProductListModule::class,
        ProductListV2BindingModule::class
    ])
    abstract fun bindProductListV2Fragment(): ProductListV2Fragment
    
    @PerFragment
    @ContributesAndroidInjector(modules = [
        ProductListModule::class,
        ProductListBindingModule::class
    ])
    abstract fun bindProductListFragment(): ProductListFragment
}

@Module
class ProductListModule {

    @Provides
    fun provideChildFragmentManager(productListFragment: Fragment) =
        productListFragment.childFragmentManager
}

@Module
abstract class ProductListBindingModule {
    @Binds
    fun bindFragment(fragment: ProductListFragment): Fragment
}

@Module
abstract class ProductListV2BindingModule {
    @Binds
    fun bindFragment(fragment: ProductListV2Fragment): Fragment
}

As for the error message itself, it tells you three things:

  • The generated ProductListV2FragmentSubcomponent requires a ProductListFragment , but there is no available binding for it.
  • The subcomponent may be able to inject dependencies into an existing ProductListFragment . This can be useful information in other situations, but it isn't relevant to what you're trying to do.
  • There is a component in your app which can provide ProductListFragment . Specifically, this is the generated ProductListFragmentSubcomponent , which takes a ProductListFragment in its factory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM