具有BaseActivity的Android Dagger 2可减少样板

时间:2017-03-25 19:08:34

标签: android dagger-2 boilerplate

当我想将每个活动中的一些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。但是我遇到了一些问题。我想也许用泛型我可以做到,但我不确切知道如何。

1 个答案:

答案 0 :(得分:5)

以下是问题:您调用了哪个@Component public interface YourComponent { void injectBase(BaseActivity baseActivity); void injectA(ActivityA activityA); void injectB(ActivityB activityB); void injectC(ActivityC activityC); } 方法,Java可以在编译时确定吗?

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

injectA

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

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

泛型在这里没有帮助:您正在寻找您的Component来生成并调用ActivityA,ActivityB和ActivityC的成员注入器。泛型将被删除,但此外组件不能采用BaseActivity的任意子类:Dagger无法在编译时为其可能仅在运行时遇到的类型生成代码。你真的需要在编译时在Dagger中准备这些类型。

解决这个问题的一种方法是允许子类型自我注入。子类型知道// in BaseActivity protected abstract void injectDependencies(); // in ActivityA @Override protected void injectDependencies() { component.injectA(this); } 是ActivityA(依此类推),即使代码看起来与字符字符相同,Java也可以识别正确的类型并正确编译它。

Map<Class, MembersInjector>

然而,还有另一个最近发布的选项,使用dagger.android,它使用Multibindings和(有效){{1}}到动态注入您想要的特定类型。这也适用于超类,也可以让你的Activity扩展DaggerActivity,一切都会按你喜欢的方式工作。 (请参阅dagger.android.support包,了解您的AppCompatActivity等效DaggerAppCompatActivity。)