我正在尝试理解Dagger 2中的组件。这是一个例子:
@Component(modules = { MyModule.class })
public interface MyComponent {
void inject(InjectionSite injectionSite);
Foo foo();
Bar bar();
}
我理解void inject()
方法的作用。但我不明白其他Foo foo()
getter方法的作用。这些其他方法的目的是什么?
答案 0 :(得分:8)
在依赖组件的层次结构的上下文中,例如在this example中,提供方法(例如Foo foo()
)用于公开对依赖组件的绑定。 "暴露"意味着"提供"甚至"发布"。请注意,方法本身的名称实际上是无关紧要的。一些程序员选择命名这些方法Foo exposeFoo()
以使方法名称反映其目的。
<强>解释强>
在Dagger 2中编写组件时,会将包含@Provides
方法的模块组合在一起。这些@Provides
方法可以被认为是&#34;绑定&#34;因为它们将抽象(例如,类型)与解决该类型的具体方式相关联。考虑到这一点,Foo foo()
方法使组件能够将Foo
的绑定公开给依赖组件。
示例:强>
让我们说Foo
是一个应用程序Singleton,我们希望将它用作DependsOnFoo
实例的依赖项,但是在范围较窄的组件中。如果我们在@Provides
的一个模块中编写一个天真的MyDependentComponent
方法,那么我们将获得一个新实例。相反,我们可以这样写:
@PerFragment
@Component(dependencies = {MyComponent.class }
modules = { MyDependentModule.class })
public class MyDependentComponent {
void inject(MyFragment frag);
}
模块:
@Module
public class MyDepedentModule {
@Provides
@PerFragment
DependsOnFoo dependsOnFoo(Foo foo) {
return new DependsOnFoo(foo);
}
}
还假设DependentComponent
的注射网站包含DependsOnFoo
:
public class MyFragment extends Fragment {
@Inject DependsOnFoo dependsOnFoo
}
请注意MyDependentComponent
只知道模块MyDependentModule
。通过该模块,它知道它可以使用DependsOnFoo
的实例提供Foo
,但它不知道如何自己提供Foo
。尽管 MyDependentComponent
是MyComponent
的依赖组件,但仍会发生。 Foo foo()
中的MyComponent
方法允许依赖组件MyDependentComponent
使用MyComponent
绑定Foo
来注入DependsOnFoo
。如果没有此Foo foo()
方法,编译将失败。
我们希望获得Foo
的实例,而无需致电inject(this)
。组件内的Foo foo()
方法允许使用Guice的Injector
或Castle Windsor的Resolve
来调用getInstance()
。图示如下:
public void fooConsumer() {
DaggerMyComponent component = DaggerMyComponent.builder.build();
Foo foo = component.foo();
}
答案 1 :(得分:8)
Dagger是一种连接对象及其依赖关系图的方法。作为直接调用构造函数的替代方法,您可以通过从Dagger请求实例,或者通过提供您希望注入Dagger创建的实例的对象来获取实例。
让我们做一家咖啡店,这取决于Provider<Coffee>
和CashRegister。假设您在模块中连接了这些(可能是LightRoastCoffee和DefaultCashRegister实现)。
public class CoffeeShop {
private final Provider<Coffee> coffeeProvider;
private final CashRegister register;
@Inject
public CoffeeShop(Provider<Coffee> coffeeProvider, CashRegister register) {
this.coffeeProvider = coffeeProvider;
this.register = register;
}
public void serve(Person person) {
cashRegister.takeMoneyFrom(person);
person.accept(coffeeProvider.get());
}
}
现在你需要得到一个CoffeeShop的实例,但它只有一个带有依赖关系的双参数构造函数。那你怎么做的?简单:您告诉Dagger在它生成的Component实例上提供工厂方法。
@Component(modules = {/* ... */})
public interface CoffeeShopComponent {
CoffeeShop getCoffeeShop();
void inject(CoffeeService serviceToInject); // to be discussed below
}
当您致电getCoffeeShop
时,Dagger会创建Provider<Coffee>
以提供LightRoastCoffee,创建DefaultCashRegister,将它们提供给Coffeeshop构造函数,然后返回结果。恭喜,您是一家全线连接的咖啡店的拥有者。
现在,所有这些都是 void
注入方法的替代方法,它采用已经创建的实例并注入其中:
public class CoffeeService extends SomeFrameworkService {
@Inject CoffeeShop coffeeShop;
@Override public void initialize() {
// Before injection, your coffeeShop field is null.
DaggerCoffeeShopComponent.create().inject(this);
// Dagger inspects CoffeeService at compile time, so at runtime it can reach
// in and set the fields.
}
@Override public void alternativeInitialize() {
// The above is equivalent to this, though:
coffeeShop = DaggerCoffeeShopComponent.create().getCoffeeShop();
}
}
所以,你有它:两种不同的风格,这两种风格都可以让你访问完全注入的对象图,而无需列出或关心他们需要的确切依赖关系。您可以更喜欢其中一种,或者更喜欢用于Android或服务用例的顶级和成员注入的工厂方法,或者任何其他类型的混合和匹配。
(注意:除了用作对象图的入口点之外,称为提供方法的无参数getter对于公开组件依赖关系的绑定也很有用, David Rawson在other answer中描述。)