Ritesh Shakya
Ritesh Shakya

Reputation: 585

Android Dagger get Parent Fragment into child fragment

I have been trying to, unsuccessfully, inject the Parent Fragment into its sub fragments for navigation purposes. I have followed a couple of different posts but I can't seem to understand what am I missing in my implementation.

I have a MainActivity that contains a ViewPager with one such page containing EventsFragment. This fragment in turn has two child fragments EventsListFragment and EventsDetailFragment. I wanted to inject EventsFragment fragment into EventsListFragment so that I can tell it to navigate to EventsDetailFragment.

I know this is probably a repetition of the posts below and I really apologize for that but I honestly cannot see what am I missing. These are the posts I've found:

My implementation is as follows:

ApplicationComponent

@Singleton
@Component(modules = [
    AndroidSupportInjectionModule::class,
    ActivityModule::class,
    BaseApplicationModule::class,
    ApplicationModule::class])
interface ApplicationComponent : AndroidInjector<AndroidApplication> {

@Component.Builder
    abstract class Builder : AndroidInjector.Builder<AndroidApplication>()
}

ActivityModule

@Module(includes = [MainActivityProvider::class])
abstract class ActivityModule{

}

MainActivityProvider

@Module(includes = [EventsFragmentProvider::class])
abstract class MainActivityProvider {
    @PerActivity
    @ContributesAndroidInjector(modules = [MainActivityModule::class])
    abstract fun provideMainActivityFactory(): MainActivity
}

EventsFragmentProvider

@Module(includes = [EventsListProvider::class, 
EventsDetailProvider::class])
abstract class EventsFragmentProvider {
    @PerFragment
    @ContributesAndroidInjector(modules = [EventsFragmentModule::class])
    abstract fun provideEventsFragmentFactory(): EventsFragment
}

EventsFragmentModule

@Module
class EventsFragmentModule {
     @Binds
     abstract fun providesEventListView(eventsFragment: EventsFragment): EventContract.Flow
}

EventsListProvider

@Module
abstract class EventsListProvider {
    @PerFragment
    @ContributesAndroidInjector(modules = [EventsListModule::class])
    abstract fun provideEventsListFragmentFactory(): EventsListFragment
}

EventsFragment

class EventsFragment : DaggerFragment(), EventContract.Flow {
    override fun navigateToList() {
        addFragment(navigator.getEventsListFragment(context!!))
    }

    override fun navigateToDetail(id: String) {
        println("id = ${id}")
    }

    ...
}

EventContract

interface EventContract {
    interface Flow {
        fun navigateToList()

        fun navigateToDetail(id: String)
    }
}

EventsListFragment

class EventsListFragment : DaggerFragment() {
    @Inject
    lateinit var eventsFlow: EventContract.Flow

    ...

}

Error

[Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] EventContract.Flow cannot be provided without an @Provides-annotated method.
public abstract interface ApplicationComponent extends dagger.android.AndroidInjector<AndroidApplication> {
            ^
      EventContract.Flow is injected at
          EventsListFragment.eventsFlow
      EventsListFragment is injected at
          dagger.android.AndroidInjector.inject(T)
  component path: ApplicationComponent →EventsListProvider_ProvideEventsListFragmentFactory.EventsListFragmentSubcomponent

I may be using a anti-pattern but this is what got me working to this point. Im open to changes that may help me achieve this

Upvotes: 0

Views: 1135

Answers (1)

jaychang0917
jaychang0917

Reputation: 1888

The error is caused by the following module:

@Module
class EventsFragmentModule {
     @Binds
     abstract fun providesEventListView(eventsFragment: EventsFragment): EventContract.Flow
}

Dagger would not provide you with a Fragment and you shouldn't do that.

Moreover, I think you misunderstand the meaning of @ContributesAndroidInjector. It means creating an AndroidInjector for you but proving an instance.

@Module
abstract class EventsListProvider {
    @PerFragment
    @ContributesAndroidInjector(modules = [EventsListModule::class])
    abstract fun provideEventsListFragmentFactory(): EventsListFragment
}

So you should pass your EventsFragment instance into the module like this post instead of using field injection.

Upvotes: 1

Related Questions