-1

I'm currently working on a android app and using dagger for dependency injection. I've run into trouble when trying to inject dependencies into fragments. I am using a service for Bluetooth that i provide in the following module.

@Module
public abstract class BluetoothModule {

    @Provides
    @Singleton
    @NonNull
    static RxBleClient provideRxBleClient(Context context) {
        RxBleClient client = RxBleClient.create(context);

        RxBleClient.setLogLevel(RxBleLog.VERBOSE);
        return client;
    }

    @Binds
    @Reusable
    @Production
    abstract IBluetoothService provideBlueToothService(BluetoothService bluetoothService);

    @Binds
    @Reusable
    @Test
    abstract IBluetoothService provideMockBlueToothService(MockBluetoothService bluetoothService);

}

Since I am using MVP pattern I wanted to inject this service into presenter(constructor injection) and then presenter into fragment (using field injection). Everything works well if I inject presenter into main activity.

@Module
public abstract class MainActivityModule {

    @Provides
    @ActivityScoped
    static MainActivityPresenter provideMainActivityPresenter(
            SchedulerProvider schedulerProvider,
            @Test IBluetoothService bluetoothService) {

        return new MainActivityPresenter(schedulerProvider, bluetoothService);
    }


}

However, When I inject BluetoothService int FragmentPresenter

@Module
public abstract class MapFragmentModule {

    @Provides
    @Reusable
    static MapPresenter provideMapPresenter(SchedulerProvider provider,
                                            @Test IBluetoothService bluetoothService) {
        return new MapPresenter(provider,bluetoothService);
    }
}

I have Following Error

error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] com.wavy.services.bluetooth.IBluetoothService cannot be provided without an @Provides-annotated method.
public interface ApplicationComponent extends AndroidInjector<DaggerApplication>{
       ^
      com.wavy.services.bluetooth.IBluetoothService is injected at
          com.wavy.ui.map.MapPresenter.<init>(…, bluetoothService)
      com.wavy.ui.map.MapPresenter is injected at
          com.wavy.ui.map.MapFragment.mapPresenter
      com.wavy.ui.map.MapFragment is injected at
          com.wavy.ui.MainActivity.mapFragment
      com.wavy.ui.MainActivity is injected at
          dagger.android.AndroidInjector.inject(T)
  component path: com.wavy.config.dagger.components.ApplicationComponent → com.wavy.config.dagger.builders.ActivityBuilder_BindMainActivity.MainActivitySubcomponent

So I have found this issue on github with similar problem as mine Issue Link

Solution was not to use @Inject annotation in Fragment constructor so i did it and after that I get another error

error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] com.wavy.ui.map.MapFragment cannot be provided without an @Inject constructor or an @Provides-annotated method. This type supports members injection but cannot be implicitly provided.
public interface ApplicationComponent extends AndroidInjector<DaggerApplication>{
       ^
  A binding with matching key exists in component: com.wavy.config.dagger.builders.FragmentBuilder_BindMapFragment.MapFragmentSubcomponent
      com.wavy.ui.map.MapFragment is injected at
          com.wavy.ui.MainActivity.mapFragment
      com.wavy.ui.MainActivity is injected at
          dagger.android.AndroidInjector.inject(T)
  component path: com.wavy.config.dagger.components.ApplicationComponent → com.wavy.config.dagger.builders.ActivityBuilder_BindMainActivity.MainActivitySubcomponent

This is how i provide my fragment

  @ContributesAndroidInjector(modules = {MapFragmentModule.class})
  abstract MapFragment bindMapFragment();

Bluetooth service

public class BluetoothService implements IBluetoothService {
        private final RxBleClient rxBleClient;

        @Inject
        public BluetoothService(RxBleClient rxBleClient) {
            this.rxBleClient = rxBleClient;
        }

//code omitted for clarity
}

Map Fragment

public class MapFragment extends BaseFragment {

    @Inject
    MapPresenter mapPresenter;

    @Inject
    public MapFragment() {
        // Required empty public constructor
    }
//code omitted for clarty
}

Map Presenter

public class MapPresenter extends BasePresenter<MapFragment> {
    private final IBluetoothService bluetoothService;

    @Inject
    public MapPresenter(SchedulerProvider schedulerProvider,
                        IBluetoothService bluetoothService) {
        super(schedulerProvider);
        this.bluetoothService = bluetoothService;
    }
    //code ommited for clarity
}

ActivityBuilder

@Module
public abstract class ActivityBuilder {

    @ActivityScoped
    @ContributesAndroidInjector(modules = {MainActivityModule.class, FragmentBuilder.class})
    abstract MainActivity bindMainActivity();

}

AppComponent

@Singleton
@Component(modules = {
        AndroidSupportInjectionModule.class,
        ApplicationModule.class,
        ActivityBuilder.class,
        BluetoothModule.class,
        RetrofitRestClientModule.class,
        RxModule.class,
        ApiModule.class,
        RoomDatabaseModule.class
})
public interface ApplicationComponent extends AndroidInjector<DaggerApplication>{

    void inject(WavyApplication application);

    @Override
    void inject(DaggerApplication instance);

    @Component.Builder
    interface Builder{
        @BindsInstance
        Builder application(Application application);
        ApplicationComponent build();

    }
}

I would much appreciate any ideas how to solve this problem, thanks for help

Dargor66
  • 33
  • 2
  • 8

1 Answers1

0

You probably forgot to include your fragment module on your activity subcomponent. You should have something like this:

abstract class MapFragmentBuilderModule {

    @ContributesAndroidInjector(modules = {MapFragmentModule.class})
    abstract MapFragment bindMapFragment();

}

and then in your activity module:

@ActivityScoped
@ContributesAndroidInjector(modules = [MainModule::class, MapFragmentBuilderModule::class])
internal abstract fun mainActivity(): MainActivity
Benjamin
  • 7,055
  • 6
  • 40
  • 60
  • Unfortunately that is not the case I have fragment module included as you presented, I have updated the code so that you can see for yourself. If there is any more code you would like me to provide please just say so. – Dargor66 Dec 18 '18 at 13:38