首页 > 解决方案 > 使用 ContributesAndroidInjector 提供 Activity

问题描述

我在向Activity需要此对象的依赖项提供对象时遇到问题。

我有一个非常标准的 Dagger 2.13 设置,如下所示:

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();
}

当我尝试使用ActivityCheckout时,WelcomeFragment我收到无法提供此依赖的错误:

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.

似乎没有提供该活动,但我不知道为什么。我试图按照其中一个教程进行相同的设置并且可以注入Activity对象。

我正在使用DaggerApplication,DaggerAppCompatActivityDaggerFragment.

标签: javaandroiddependency-injectiondagger-2

解决方案


虽然我不确定它如何/为什么会显示您所显示的错误,但您在@Singleton 范围内错误地注册了活动范围内的事物。请注意,您发布的错误消息抱怨未提供 ActivityCheckout;如果无法提供您的活动,您可能会发现一条错误消息,提示您没有 MainActivity。

我的预感是您的编译中有多个错误,但您只发布了最后一个错误,并且较早的错误表明您无法将@Singleton 绑定安装到@ContributesAndroidInjector 默认创建的无范围子组件中。因此,Dagger 会忽略该 @Provides 方法,并且您会得到错误。

@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);
}

相反,创建一个特定于活动的范围,这表明每个活动都有自己的。

@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.

现在用它标记您的@ContributesAndroidInjector,以便您生成的子组件采用该范围:

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

您的绑定也是如此,因此它们与您的活动组件的生命周期相匹配:

@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);
  }
}

推荐阅读