0

I am able to inject Activities, BroadcastReceviers etc..., but when I try to inject a Fragment the same way I get the following exception:

.../AppComponent.java:8: error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] java.util.Map<java.lang.String,javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>>> cannot be provided without an @Provides-annotated method.
    public abstract interface AppComponent extends dagger.android.AndroidInjector<com.inepex.simpleclient.App> {
                    ^
          java.util.Map<java.lang.String,javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>>> is injected at
              dagger.android.DispatchingAndroidInjector.<init>(…, injectorFactoriesWithStringKeys)
          dagger.android.DispatchingAndroidInjector<android.support.v4.app.Fragment> is injected at
              com.inepex.tracker.SimpleTrackerApp.fragmentInjector
          com.inepex.simpleclient.App is injected at
              dagger.android.AndroidInjector.inject(T)

I followed this description: https://code.luasoftware.com/tutorials/android/dagger2-injection-for-fragment/

Update:

I would like to have a Fragment instance because I would likee to switch fragments like this:

Fragment fragment = new WelcomeFragment();

FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.contentFragment, fragment);
transaction.commit();

Injecting the Fragment:

class MainActivity : BaseActivity() {

    @Inject
    lateinit var welcomeFragment: WelcomeFragment

    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ButterKnife.bind(this)
    }
}

Component:

@Component(modules = arrayOf(AndroidInjectionModule::class, AppModule::class, AbstractAppModule::class, AbstractLibModule::class, LibModule::class))
@Singleton
interface AppComponent : AndroidInjector<App> {

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: App): Builder

        fun build(): AppComponent
    }
}

Module:

@Module
abstract class AbstractAppModule {

    @ContributesAndroidInjector
    internal abstract fun welcomeFragment(): WelcomeFragment

    @ContributesAndroidInjector
    internal abstract fun mainActivity(): MainActivity

    @ContributesAndroidInjector
    internal abstract fun onboardingActivity(): OnboardingActivity
}

App:

open class SimpleTrackerApp : MultiDexApplication(),
        HasActivityInjector,
        HasServiceInjector,
        HasBroadcastReceiverInjector,
        HasSupportFragmentInjector {


    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

    @Inject
    lateinit var dispatchingServiceInjector: DispatchingAndroidInjector<Service>

    @Inject
    lateinit var dispatchingBroadcastReceiverInjector: DispatchingAndroidInjector<BroadcastReceiver>

    @Inject
    lateinit var fragmentInjector: DispatchingAndroidInjector<Fragment>

    override fun activityInjector(): AndroidInjector<Activity> = dispatchingAndroidInjector

    override fun serviceInjector(): AndroidInjector<Service> = dispatchingServiceInjector

    override fun broadcastReceiverInjector(): AndroidInjector<BroadcastReceiver> =
            dispatchingBroadcastReceiverInjector

    override fun supportFragmentInjector(): DispatchingAndroidInjector<Fragment> = fragmentInjector
balint.steinbach
  • 278
  • 3
  • 16

2 Answers2

0

UPDATED:

I noticed that you using android.support.v4.app.Fragment, but you using Fragment from app. You need to add

implementation 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries

Also, activity needs to implement HasFragmentInjector interface

public class YourActivity extends Activity
    implements HasFragmentInjector {
  @Inject DispatchingAndroidInjector<Fragment> fragmentInjector;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);
    // ...
  }

  @Override
  public AndroidInjector<Fragment> fragmentInjector() {
    return fragmentInjector;
  }
}

UPDATED:

First, you need to inject fragment before on create

Finally, in your Activity.onCreate() method, call AndroidInjection.inject(this) before calling super.onCreate();:

public class YourActivity extends Activity {
  public void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);
  }
}

Docs

Did you add this module?

@Module abstract class FragmentModule {
    @ContributesAndroidInjector
    internal abstract fun contributePhotoPinListFragment(): PhotoPinListFragment
}

To AppComponent:

@Singleton
@Component(modules = [..., (FragmentModule::class)])
interface AppComponent {
Ihor Bykov
  • 1,843
  • 3
  • 15
  • 22
  • Hi Igor, yes I have this in the module and the component. – balint.steinbach Oct 11 '18 at 09:25
  • @balint.steinbach I mean, did you add a module to the component. Just double checking :) – Ihor Bykov Oct 11 '18 at 09:27
  • @balint.steinbach I updated answer, when saw you activity – Ihor Bykov Oct 11 '18 at 09:34
  • sorry my mistake, still the same issue. Is it possible to do this in the Activity at all?: @Inject lateinit var welcomeFragment: WelcomeFragment – balint.steinbach Oct 13 '18 at 13:56
  • @balint.steinbach 1. you don't need to inject welcomeFragment in activity. 2. You need to implement HasSupportFragmentInjector in your activity – Ihor Bykov Oct 13 '18 at 15:39
  • I need the instance because I would like to switch the fragments for the activity. I added an update to my question. Thanks – balint.steinbach Oct 15 '18 at 08:02
  • @balint.steinbach Ok, got it. I thought you want to inject other objects to the fragemnt. Then you need to @Provide fragment that you want to inject. `ContributesAndroidInjector` is used to inject other dependency into fragment – Ihor Bykov Oct 15 '18 at 08:25
-1

Looks like you didn't add provider for the Fragment in the module. Dagger doesn't know how to find the object of the Fragment you're trying to inject. So inside the module class you have to create a provide as below (just an example)

@Provides
@Singleton
fun provideFragment(): Fragment = Fragment()
Pritam Karmakar
  • 2,773
  • 5
  • 30
  • 49