Search code examples
javaandroiddagger-2dagger

Dagger-Android Activity injection with inheritance: "This type supports members injection but cannot be implicitly provided."


I have three activities, which are related by inheritance.

Only one of these activities uses fragment injection.

Two of the activities require Dagger 2 activity injection. The third activity does not require any injection.

Here are my activities:

/**
 * Needs activity injection.
 */
class ThirdActivity extends SecondActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // calls the super, which will call AndroidInjection.inject(this);
        // ... other code not shown
    }
}

/**
 * This activity requires fragment injection
 */
class SecondActivity extends FirstActivity
{

    @Inject
    DispatchingAndroidInjector<Fragment> fragmentInjector;

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

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

/**
 * Does not use injection.
 */
class FirstActivity extends Activity
{
    // no injection required
}

Here are my Dagger 2 modules

@Module
abstract class AppModule
{
    @ActivityScope
    @ContributesAndroidInjector(modules = {ThirdActivityModule.class, SecondActivityModule.class})
    abstract ThirdActivity contributeThirdActivityInjector();

    @ActivityScope
    @ContributesAndroidInjector(modules = {SecondActivityModule.class})
    abstract SecondActivity contributeSecondActivityInjector();
}

@Module
abstract class SecondActivityModule
{
    @Binds
    abstract Activity bindActivity(SecondActivity secondActivity);

    @FragmentScope
    @ContributesAndroidInjector(modules = {MyFragmentModule.class})
    abstract MyFragment contributeMyFragmentInjector();
}

@Module
public abstract class ThirdActivityModule
{
    @Binds
    abstract Activity bindActivity(ThirdActivity thirdActivity);
}

@Module
abstract class MyFragmentModule
{
    @Binds
    abstract Fragment bindFragment(MyFragment mFragment);
}

The error I'm getting is this:

Note: Recompile with -Xlint:unchecked for details.
/dagger/AppComponent.java:45: error: [Dagger/MissingBinding] 
[dagger.android.AndroidInjector.inject(T)] 
com.example.SecondActivity cannot be provided without an @Inject constructor or an @Provides-annotated method. 
This type supports members injection but cannot be implicitly provided.

I think this might be because I've included both SecondActivityModule and ThirdActivityModule in the contributesThirdActivityInjector() call, but I'm not sure.

Any help/advice with activity/fragment injection in the case of inheritance would be appreciated.


Solution

  • In ThirdActivityModule, try to change the return type of bindActivity to SecondActivity:

    @Module
    public abstract class ThirdActivityModule {
        /**
         * Upcasts ThirdActivity to SecondActivity. SecondActivityModule will do
         * the rest to upcast it to Activity.
         */
        @Binds
        abstract SecondActivity bindActivity(ThirdActivity thirdActivity);
    }
    

    I suspect that Dagger wants an Activity to fulfil dependency requests somewhere, and by the @Binds rule of SecondActivityModule.bindActivity Dagger has to somehow obtain a SecondActivity.

    Then this modified ThirdActivityModule.bindActivity lets Dagger know it can treat ThirdActivity as a SecondActivity.