简体   繁体   中英

Provide Activity using ContributesAndroidInjector

I have a problem providing Activity object to dependecines that needs this object.

I have a pretty standard setup with Dagger 2.13 like following:

AppComponent.java

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AppModule.class,
        ActivityModule.class
})
public interface AppComponent extends AndroidInjector<Appname> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Appname appname);
        AppComponent build();
    }

    void inject(Appname appname);
}

ActivityModule.java

@Module
abstract public class ActivityModule {
    @ContributesAndroidInjector(modules = {MainActivityModule.class, MainActivityFragmentsModule.class})
    abstract MainActivity contributeMainActivity();
}

MainActivityModule.java

@Module
public class MainActivityModule {

@Provides
@Singleton
static Billing provideBilling(Context context) {
    return new Billing(context);
}

@Provides
@Singleton
static ActivityCheckout provideActivityCheckout(MainActivity activity, Billing billing) {
    return ActivityCheckout.forActivity(activity, billing);
}
}

MainActivityFragmentsModule.java

@Module
abstract public class MainActivityFragmentsModule {
    @ContributesAndroidInjector
    abstract WelcomeFragment contributeWelcomeFragment();
}

When I'm trying to use ActivityCheckout in WelcomeFragment I'm getting error that this dependecy cannot be provided:

Error:(20, 8) error: [dagger.android.AndroidInjector.inject(T)] org.solovyev.android.checkout.ActivityCheckout cannot be provided without an @Inject constructor or from an @Provides-annotated method.

It seems like the activity is not provided, but I have no idea why. I was trying to follow one of the tutorials where was the same setup and it was possible to inject Activity object.

I'm using DaggerApplication , DaggerAppCompatActivity and DaggerFragment .

Though I'm not sure how/why it would show the error you're showing, you are misregistering activity-scoped things under @Singleton scope. Note that the error message you posted complains about ActivityCheckout not being provided; if your activity were not able to be provided, you'd likely find an error message about the absence of MainActivity instead.

My hunch is that there are multiple errors in your compile, but you only posted the last one, and that earlier ones reveal that you can't install @Singleton bindings into the unscoped subcomponent that @ContributesAndroidInjector creates by default. Consequently, Dagger ignores that @Provides method, and you get the error you get.

@Provides
@Singleton  // BAD: If this is Singleton, it will outlive and leak MainActivity.
            // Dagger will complain about mismatched scopes, but it's right:
            // It doesn't make sense for ActivityCheckout to be @Singleton.
static ActivityCheckout provideActivityCheckout(
    MainActivity activity, Billing billing) {
  return ActivityCheckout.forActivity(activity, billing);
}

Instead, create a scope specific to activities, which indicates that each activity gets its own.

@Retention(RetentionPolicy.RUNTIME)    // Not used at runtime, but JSR-330
@Scope                                 // requires that @Scopes are kept at RUNTIME.
public @interface ActivityScope {}     // PerActivity is also a good name.

Now mark your @ContributesAndroidInjector with it, so your generated subcomponent takes that scope:

@ContributesAndroidInjector(
    modules = {MainActivityModule.class, MainActivityFragmentsModule.class})
@ActivityScope
abstract MainActivity contributeMainActivity();

And your bindings too, so they match the lifetime of your activity component:

@Module public class MainActivityModule {
  // I'm assuming this is actually activity scoped, but if it's truly singleton,
  // leave it @Singleton and move it to AppModule.
  @Provides
  @ActivityScope
  static Billing provideBilling(Context context) {
    return new Billing(context);
  }

  @Provides
  @ActivityScope
  static ActivityCheckout provideActivityCheckout(
      MainActivity activity, Billing billing) {
    return ActivityCheckout.forActivity(activity, billing);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM