是否可以避免在父类中进行不必要的注入?

时间:2017-06-12 03:13:49

标签: android dagger-2

给出以下示例:

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

1 个答案:

答案 0 :(得分:0)

Dagger无法做到这一点,但你可以自己做。

同意并在评论中扩展您的观点:

  

是的,这是必要的。如果我们仅在父母身上使用注射,Dagger不会注入子对象。但是,如果从子对象调用它,它会注入父对象。

这是正确的,并在"A note about covariance"中注明:虽然inject(Foo)可以接受Foo或其任何子类的实例,但Dagger是编译时框架;不会生成inject(Foo)来注入属于Foo的任意子类的字段,因为在编译时不可能知道。这可能有点令人惊讶,特别是如果您的Component同时具有inject(Foo)inject(FooSubclass),就像您在此处使用CustomView和SecondaryCustomView一样:使用名称injectCustomViewinjectSecondaryCustomView,这将是显而易见的只有前者可以从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,因此这与您的特定情况一样接近。