Dagger 2.10/2.11 injecting Activity failing

2019-03-16 05:24发布

问题:

I have been trying to, unsuccessfully, inject the Activity in a class ViewUtils. I have followed a couple of different posts but I can't seem to understand what am I missing in my implementation.

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:

  • Dagger 2.10 Android subcomponents and builders
  • How to create custom scoped modules in dagger 2.10
  • https://google.github.io/dagger/subcomponents.html

My implementation is as follows:

AppComponent

@Component(modules = {
        AppModule.class, AndroidSupportInjectionModule.class, ActivityBindingModule.class
}) @Singleton public interface AppComponent extends AndroidInjector<EmblyApp> {

    @Component.Builder abstract class Builder extends AndroidInjector.Builder<EmblyApp> {}
}

ActivityBindingModule

@Module public abstract class ActivityBindingModule {

    @ContributesAndroidInjector
    abstract LoginActivity loginActivity();
}

LoginSubcomponent

@Subcomponent(modules = LoginSubcomponent.LoginActivityModule.class)
public interface LoginSubcomponent extends AndroidInjector<LoginActivity> {

    @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<LoginActivity> {}

    @Module abstract class LoginActivityModule {

        @Binds abstract Activity bindActivity(LoginActivity activity);

        @Provides @ActivityScope static ViewUtils viewUtils(Activity activity) {
            return new ViewUtils(activity);
        }
    }
}

ViewUtils

public class ViewUtils {

    private final Activity activity;

    @Inject public ViewUtils(Activity activity) {
        this.activity = activity;
    }
}

And the error i'm getting is:

Error:(14, 22) error: [dagger.android.AndroidInjector.inject(T)] android.app.Activity cannot be provided without an @Inject constructor or from an @Provides-annotated method.
android.app.Activity is injected at
com.emblyapp.app.ui.helpers.ViewUtils.<init>(activity)
com.emblyapp.app.ui.helpers.ViewUtils is injected at
com.emblyapp.app.ui.authentication.login.LoginActivity.viewUtils
com.emblyapp.app.ui.authentication.login.LoginActivity is injected at
dagger.android.AndroidInjector.inject(arg0)

What is wrong in here? Thanks for the help!

Edit: I forgot to mention my LoginActivity has the injection with the AndroidInjection

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

回答1:

As specified in dagger android documentation:

Pro-tip: If your subcomponent and its builder have no other methods or supertypes than the ones mentioned in step #2, you can use @ContributesAndroidInjector to generate them for you. Instead of steps 2 and 3, add an abstract module method that returns your activity, annotate it with @ContributesAndroidInjector, and specify the modules you want to install into the subcomponent. If the subcomponent needs scopes, apply the scope annotations to the method as well.

Thus, we can get rid of LoginSubcomponent and perform following changes in ActivityBindingModule:



    @Module
    public abstract class ActivityBindingModule {

        @ActivityScope
        @ContributesAndroidInjector(modules = LoginActivityModule.class)
        abstract LoginActivity loginActivity();
    }


LoginActivityModule.java



    @Module
    abstract class LoginActivityModule {

        @Binds
        abstract Activity bindActivity(LoginActivity activity);

        @Provides
        @ActivityScope
        static ViewUtils viewUtils(Activity activity) {
            return new ViewUtils(activity);
        }
    }


Your custom application class:



    public class MyApp extends DaggerApplication {

        @Inject
        DispatchingAndroidInjector dispatchingActivityInjector;

        @Override
        protected AndroidInjector applicationInjector() {
            return DaggerAppComponent.builder().create(this);
        }

    }