给出以下示例:
class CustomView extends View {
@Inject
SomeObject mObject;
@Override
protected void onFinishInflate() {
super.onFinishInflate();
getApplicationComponent().inject(this);
}
}
class SecondaryCustomView extends CustomView {
@Inject
AnotherObject mAnotherObject;
@Override
protected void onFinishInflate() {
super.onFinishInflate();
getApplicationComponent().inject(this);
}
}
两个自定义视图都可以独立用于布局。第二个比第一个更专业。
如您所见,两者都有要注入的字段,都需要调用inject()。问题是,当SecondaryCustomView调用其inject()时,Dagger会注入AnotherObject的实例和SomeObject的实例。在调用super.onFinishInflate()之后,它创建了SomeObject的第二个实例。这本身不是问题,但我们至少会创建不必要的对象。
有没有办法避免这种情况?有些方法告诉Dagger注射了一个子类,所以忽略父注射?
例如,Component看起来像这样:
@Component(...)
public interface AppComponent {
void inject(CustomView);
void inject(SecondaryCustomView);
}
答案 0 :(得分:0)
Dagger无法做到这一点,但你可以自己做。
同意并在评论中扩展您的观点:
是的,这是必要的。如果我们仅在父母身上使用注射,Dagger不会注入子对象。但是,如果从子对象调用它,它会注入父对象。
这是正确的,并在"A note about covariance"中注明:虽然inject(Foo)
可以接受Foo或其任何子类的实例,但Dagger是编译时框架;不会生成inject(Foo)
来注入属于Foo的任意子类的字段,因为在编译时不可能知道。这可能有点令人惊讶,特别是如果您的Component同时具有inject(Foo)
和inject(FooSubclass)
,就像您在此处使用CustomView和SecondaryCustomView一样:使用名称injectCustomView
和injectSecondaryCustomView
,这将是显而易见的只有前者可以从Foo中调用。
除了简单地将injectedAlready
布尔字段设置为标志外,一种技术是创建一个可覆盖的方法,该方法不会调用其超类实现:
class CustomView extends View {
@Inject
SomeObject mObject;
@Override
protected void onFinishInflate() {
injectMe();
super.onFinishInflate();
}
protected void injectMe() {
getApplicationComponent().inject(this); // inject(CustomView);
}
}
class SecondaryCustomView extends CustomView {
@Inject
AnotherObject mAnotherObject;
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// ...
}
/** Despite looking identical, the JVM can call the more-specific overload here. */
@Override protected void injectMe() {
getApplicationComponent().inject(this); // inject(SecondaryCustomView)
}
}
如果您正在为Activity和Fragment类寻找类似的解决方案,可以使用dagger.android;内置机制使用类的运行时类型从Map动态获取正确的AndroidInjector。但是,该解决方案目前不支持View,因此这与您的特定情况一样接近。