Vij*_*ede 5 java android dependency-injection dagger-2
我在Android应用程序中使用Dagger2.0.
我对@Inject注释很困惑.我有两个实现相同接口的具体类.我正在使用@Inject注释注入一个具体类.这里,@ Inject注释如何决定实例化哪个具体类.
例:
我有一个界面.
Product.java
public interface Product {}
Run Code Online (Sandbox Code Playgroud)
ProductOne和ProductTwo共有两个具体的类.
ProductOne.class
public class ProductOne implements Product{
@Inject
public ProductOne() {}
}
Run Code Online (Sandbox Code Playgroud)
包装类是客户端.
Packaging.java
public class Packaging{
@Inject
public Packaging(Product product){}
}
Run Code Online (Sandbox Code Playgroud)
直到这一刻,我的包类使用了ProductOne类的实例.
混乱:
如果我有另一个具有@Inject批注的具体类ProductTwo.
public class ProductTwo implements Product {
@Inject
public ProductTwo() {}
}
Run Code Online (Sandbox Code Playgroud)
现在在我的Packaging类中,我想使用ProductTwo类的实例,那么这个@Inject注释会在这个时候起作用吗?
这个例子不会工作。对于这种情况,我们必须使用@Named注释。
对于上面的例子,在我们的 Dagger Packaging 模块中,我们必须提供ProductOne依赖ProductTwo项。
@Provides @Named("product one") Product provideProductOne() {
return new ProductOne();
}
@Provides @Named("product two") Product provideProductTwo() {
return new ProductTwo();
}
Run Code Online (Sandbox Code Playgroud)
现在,当我们需要注入这个依赖项时,我们可以通过以下方式注入它。
public class Packaging{
Product product;
@Inject
public Packaging(@Named("product one") Product product){
this.product = product;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们需要 ProductTwo 的实例。
public class Packaging{
Product product;
@Inject
public Packaging(@Named("product two")Product product){
this.product = product;
}
}
Run Code Online (Sandbox Code Playgroud)
该@Named注释只不过是使用@Qualifier包含在javax.inject
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
String value() default "";
}
Run Code Online (Sandbox Code Playgroud)
我们不必提供此声明,因此 Dagger 会为我们做这件事。
我假设,由于您没有提及模块或组件,因此您对它们以及它们如何协同工作不太熟悉。
您的示例将不起作用,因为 Dagger 2 不知道为了生成 Product 它需要使用 ProductOne 或 ProductTwo 类之一。即使 Dagger 2 会处理它们(因为它们都被标记为 @Inject),它也不会自动假设仅仅因为它们实现了 Product 就应该在那里使用它们。其原因是,当有多个(如本例所示)时,它不知道该使用哪一个。
因此,您必须使用 Product 接口从 ProductOne 或 ProductTwo 创建绑定。您可以通过模块来完成此操作。
@Module
public class ProductOneModule {
@Provides Product provideProduct(ProductOne productOne) {
return productOne;
}
}
Run Code Online (Sandbox Code Playgroud)
模块仅提供一组可重用的绑定。除非它们被组件使用,否则它们不会被实际使用(或验证)。组件是封装所有这些信息并管理它们的创建的东西,使用模块及其绑定和为带有 @Inject 构造函数的类创建的工厂。
如果您创建这样的组件,那么 dagger 2 将失败,因为如上所述,它不知道如何生成产品。
@Component
public interface PackagerOneComponent {
Packager packager();
}
Run Code Online (Sandbox Code Playgroud)
错误将是这样的:
如果没有 @Provides 注释的方法,则无法提供产品。
包装机.(产品产品)
【参数:产品产品】
这意味着当尝试创建Packager对象时,它无法为其Product参数找到合适的绑定。解决这个问题的方法是指定模块及其绑定 from Product < ProductOne。
@Component(modules = ProductOneModule.class)
public interface PackagerOneComponent {
Packager packager();
}
Run Code Online (Sandbox Code Playgroud)
现在它知道要创建一个Product它需要调用ProductOneModule.provideProduct(ProductOne),并且为了调用它需要创建一个ProductOne它知道如何执行的操作,因为您已经用 标记了它的构造函数之一@Inject。
当然,如果您想使用 ProductTwo 那么您可以创建另一个模块和组件。
@Module
public class ProductTwoModule {
@Provides Product provideProduct(ProductTwo productTwo) {
return productTwo;
}
}
@Component(modules = ProductTwoModule.class)
public interface PackagerTwoComponent {
Packager packager();
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下使用限定符(无论是自定义限定符还是命名限定符)的问题在于,使用限定符将注入点与特定实现紧密耦合。在某些情况下,这绝对是必需的,例如,如果您有两个 Long 实例,其中一个是超时,另一个是端口,您不希望它们混淆,因此您肯定需要使用限定符来区分它们。
但是,在这种情况下,某些用户或包装可能希望使用 ProductOne,而另一些用户或包装希望使用 ProductTwo。否则,Packager 应该直接获取 ProductOne 或 ProductTwo 并避免使用该接口。
这种方法允许代码的两个不同部分将 Packager 与两种不同的实现一起使用Product,例如您的生产和测试。
当然,即使使用限定符注释,您也可以使用两种不同的实现,但您仍然必须使用各种这种技术。
| 归档时间: |
|
| 查看次数: |
1913 次 |
| 最近记录: |