当我想把每个活动中的匕首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。但我有一些问题要做。我想也许用泛型我能做到,但我不知道具体怎么做。
最佳答案
问题是:你调用哪一个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
而不能调用任何特定的子类型。重要的是,即使所有的名称都相同(如injectBase
)、injectA
,这仍然是正确的。jvm将选择它在编译时可以确定的最窄的重载,即inject
,它将注入baseactivity的字段,而不在子类型中注入任何内容。如果您将它们命名为唯一的,您将看到您调用的是哪一个,以及为什么它不注入子类型字段。泛型在这里没有帮助:您正在寻找组件来生成和调用ActivityA、ActivityB和ActivityC的成员注入器。泛型将被删除,但是组件不能接受baseactivity的任意子类:dagger不能在编译时为它可能只在运行时遇到的类型生成代码。你真的需要在编译时准备这些类型。
一种解决方法是允许子类型注入它们自己。子类型知道
inject(BaseActivity)
是AccVyTyA(等等),即使代码看起来像字符一样,Java也可以识别正确的类型并正确编译它。// in BaseActivity
protected abstract void injectDependencies();
// in ActivityA
@Override protected void injectDependencies() { component.injectA(this); }
不过,还有另一个最近发布的选项,使用dagger.android,它使用多绑定和(有效地)a
this
动态注入所需的特定类型。这也适用于从超类,到你可以让你的活动扩展匕首活动,一切都将按照你想要的方式工作。(请参阅dagger.android.support包以获取与appcompativity等效的DaggerAppCompatActivity)关于android - 具有BaseActivity的Android Dagger 2可减少样板,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43020736/