我有应用范围内的组件(仅包含Singletons),可以通过静态方法App.getComponent();
访问。我的组件包含方法void inject(MainActivity activity)
,它工作正常。我也有void inject(TaskRepo repo)
,但是这个不起作用。在TaskRepoImpl()
中,我调用:App.getComponent().inject(this);
,但它不会注入任何东西。我确定我用@Inject
注释了公共成员。
使用TaskRepo repo = App.getComponent().taskRepo();
之类的方法注入效果很好。那么,为什么匕首会忽略这些成员?
答案 0 :(得分:1)
简而言之,您需要将方法设为void inject(TaskRepoImpl impl)
;您不能只接受TaskRepo。 in the Component docs under "A note about covariance"说明了您的情况。
Dagger是一个编译时框架:在 compile时 Dagger将查看您的Component并根据Component(及其Modules)上的方法编写实现。其中一些方法可能是members injection methods(与上面的链接相同),它们是单参数方法,用于设置@Inject
字段并为传入的实例调用@Inject
方法。这些通常是void
个名为inject
的方法,但是它们可以命名为任何东西,它们也可能返回它们注入的实例(用于链接)。
诀窍是, Dagger只能预见您定义的特定类型上的字段和方法,而不能预见其子类:如果创建成员注入方法void inject(Foo foo)
,则只有Foo可以即使Foo的子类Bar具有@Inject
注释的方法,字段和方法也很重要。即使您的Dagger图同时了解Foo和Bar,也不会了解其他Foo子类,也不必准备注入它们(因为所有这些都在编译时发生)。对于“供应方法”(组件上的零参数工厂/ getter)来说,这也不是问题,因为只要Dagger知道如何为绑定创建特定的具体类型,它就可以注入该具体类型并将其返回为其超类型或接口。
因此,将注入切换到实际实现类可以避免此问题,因为Dagger可以在编译时检查实现类TaskRepoImpl,并确保它具有TaskRepoImpl在其{{1}中定义的绑定}注释的方法和字段。
@Inject
作为补充,构造函数注入使您可以通过使用@Component(modules = {...}) public interface YourComponent {
/**
* Only injects the fields and methods on TaskRepo, which might do
* nothing--especially if TaskRepo is just an interface.
*/
void inject(TaskRepo taskRepo);
/**
* Injects the fields and methods on TaskRepoImpl, TaskRepo, and
* any other superclasses or interfaces.
*/
void inject(TaskRepoImpl taskRepoImpl);
/**
* Gets a TaskRepo implementation. If you've bound TaskRepo to TaskRepoImpl,
* Dagger _can_ inject all of TaskRepoImpl's fields, because it knows at
* compile time that there's a TaskRepoImpl instance to inject.
*/
TaskRepo taskRepo();
}
字段并避免部分构造(构造但未注入)实例更好地封装类。我建议在可能的情况下使用构造函数注入,强烈建议不要对同一种类型的字段注入和构造函数注入使用 。 (除了调试您的案例,您可能没有做其他事情,但是我在这里也留了注释,以供将来的读者使用。)