Reputation: 2699
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
.
Upvotes: 0
Views: 2388
Reputation: 95614
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);
}
}
Upvotes: 3