【问题标题】:Android Dagger 2 with BaseActivity to reduce boilerplateAndroid Dagger 2 与 BaseActivity 以减少样板
【发布时间】:2017-03-25 19:08:33
【问题描述】:

我想将每个活动中的一些 Dagger 2 样板代码移动到 BaseActivity 时遇到了一些麻烦。

BaseActivity extends AppCompatActivity

我有多项活动,例如:

ActivityA extends BaseActivity implements InterfaceA;
ActivityB extends BaseActivity implements InterfaceB;
...

在每个活动中,我都有这样的方法(其中 X 是每个活动的 A、B、C、...):

public void initActivity() {
   ComponentX compX;
   ...
   compX = appComponent.plus(new ModuleX(this)); // this == InterfaceX
   ...
   compX.inject(this); // this == ActivityX
}

我试图减少此代码,将其移至父 BaseActivity。但我在做这件事时遇到了一些问题。我认为也许使用泛型我可以做到,但我不知道具体怎么做。

【问题讨论】:

    标签: android dagger-2 boilerplate


    【解决方案1】:

    这里的问题是:您调用的是哪个inject 方法,Java 可以在编译时确定吗?

    "A note about covariance" 中所述,Dagger 将为您定义的任何成员注入方法生成代码,但您传入的静态类型。

    @Component public interface YourComponent {
      void injectBase(BaseActivity baseActivity);
      void injectA(ActivityA activityA);
      void injectB(ActivityB activityB);
      void injectC(ActivityC activityC);
    }
    

    当调用injectA 并传递一个ActivityA 实例时,您将获得ActivityA 中定义的字段的注入,包括BaseActivity 中的字段。与 ActivityB 和 ActivityC 相同。但是,如果你调用injectBase,Dagger 只会注入属于 BaseActivity 的字段,即使你传入的对象恰好是 ActivityA、ActivityB 或 ActivityC。 Dagger 在编译时生成代码,所以如果你调用injectBase,注入只会发生在 BaseActivity 上的字段——因为那是为 BaseActivity 的成员注入器生成的代码,而这些是 Dagger 知道如何注入的唯一字段一个 BaseActivity 参数。

    自然因为BaseActivity只知道this是BaseActivity的一个子类型,所以它只能调用injectBase而不是任何具体的子类型。重要的是,即使所有名称 injectBaseinjectA都相同(如 inject),这仍然适用。 JVM 将选择它在编译时可以确定的最窄的重载,这将是inject(BaseActivity),它将注入 BaseActivity 的字段而不是子类型中的任何内容。如果您要对它们进行唯一命名,您会看到您调用的是哪一个,以及它为什么不注入子类型字段。

    泛型在这里无济于事:您正在寻找您的组件来生成和调用 ActivityA、ActivityB 和 ActivityC 的成员注入器。泛型将被删除,但此外组件不能采用 BaseActivity 的任意子类:Dagger 无法在编译时为它可能只在运行时遇到的类型生成代码。您确实需要在编译时在 Dagger 中准备这些类型。

    解决此问题的一种方法是允许子类型自行注入。子类型知道 this 是 ActivityA(等等),即使代码看起来逐字符相同,Java 也可以识别正确的类型并正确编译。

    // in BaseActivity
    protected abstract void injectDependencies();
    
    // in ActivityA
    @Override protected void injectDependencies() { component.injectA(this); }
    

    但是,最近发布的另一个选项是使用dagger.android,它使用多重绑定和(有效地)Map<Class, MembersInjector>动态注入您想要的特定类型。这也适用于超类,直到您可以让您的 Activity 扩展 DaggerActivity 并且一切都将按照您想要的方式工作。 (请参阅 dagger.android.support 包以获取等效的 AppCompatActivity DaggerAppCompatActivity。)

    【讨论】:

      猜你喜欢
      • 2016-09-22
      • 1970-01-01
      • 2021-01-16
      • 1970-01-01
      • 1970-01-01
      • 2016-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多