Dagger2将范围标记添加到组件的目的是什么?

时间:2015-12-21 13:46:36

标签: android dependency-injection dagger-2

我创建了一个组件,它只能持续活动的生命周期。我没有使用任何范围注释,只有组件生命周期的快速示例如下所示:

public class MainActivity extends AppCompatActivity {

private final String TAG = getClass().getSimpleName();
@Inject
AlmondButter someAlmondButter;
@Inject
CashewSandwich sandwich;

SandwichComponent sandwichComponent;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    /*create thte dependent butter for the sandwich here*/
    ButterComponent butterComponent=DaggerButterComponent.builder().
            butterModule(new ButterModule()).build();
    /*create a scope sandwichcomponent here */

    sandwichComponent=DaggerSandwichComponent.builder().sandwichModule(new SandwichModule()).
            butterComponent(butterComponent)
            .build();
    //finally we have a sandwichComponent, lets inject our dependencies
    sandwichComponent.inject(this);

    Log.v(TAG,sandwich.toString());
    Log.v(TAG,someAlmondButter.toString());
}

@Override
protected void onDestroy() {
    super.onDestroy();
    //not necessary but it clearly shows the scope being tied to lifecycle of activity
    sandwichComponent=null;
}

}

我的所有组件都没有使用anotations进行作用,并且工作正常。所以我很困惑为什么有人建议创建范围标签,有什么目的?我将在下面向您展示我的组件以供参考:

    @Component(dependencies = ButterComponent.class, modules = SandwichModule.class)
public interface SandwichComponent {
    CashewSandwich ProvideCashewSandwitch();
    void inject (MainActivity mainactivity);
}

和下一个组成部分:

    @Component(modules={ButterModule.class})

public interface ButterComponent {
     //these are for our whatever class depends on butter
     AlmondButter ProvideAlmondButter();
     CashewButter ProvideCashewButter();
}

更新:对于任何需要帮助理解这些概念的人,我制作了一个博客HERE.

2 个答案:

答案 0 :(得分:2)

通过在模块提供程序方法的组件和范围上使用范围,您可以让Dagger2为您创建scoped providers

为了在模块的provider方法中获取作用域提供者,您还必须将作用域放在组件上。

您只能在给定组件上指定一个范围,而在范围组件中,您只能在其提供者方法上具有该范围的模块,或者提供者方法也可以是未范围的。

无范围提供程序会在每次注入调用时为您提供一个新实例。 Scoped提供程序为每个特定组件实例的注入调用存储一个实例。

@Component(modules={HelloModule.class})
@Singleton
public interface HelloComponent {
    Hello hello();
    World world();

    void inject(MainActivity mainActivity);
}

@Module
public class HelloModule {
    @Provides
    public Hello hello() { return new Hello(); } //new instance each call to inject

    @Provides
    @Singleton
    public World world() { return new World(); } //one instance per component
}

值得注意的是,如果您使用另一个组件来继承其依赖项(使用子组件或组件依赖项),则只能依赖于另一个范围的组件。可以想象它是如何在Java中不允许“多重继承”的,你也不能依赖多个范围的组件并继承它们的依赖关系,只有一个。

通常,您有一个单例范围,并根据应用程序中模块的顶级分隔来子集化组件。

@Component(modules={ApplicationModule.class})
@Singleton
public interface ApplicationComponent {
    Something something();
}

@Component(dependencies={ApplicationComponent.class}, modules={MainActivityModule.class}) 
@ActivityScope 
//this is a subscoped component that inherits from ApplicationComponent
public interface MainActivityComponent extends ApplicationComponent {
    OtherThing otherThing();

    void inject(MainActivity mainActivity);
}

据Martin Fowler所说,the right way to slice your application into pieces on the top-level is by features, such as GalleryComponent, SettingsComponent, etc. and not by layers (data, domain, presentation).

答案 1 :(得分:1)

范围管理跨同一类型的多个请求的实例创建。想象一下,如果你有这个:

@Inject
AlmondButter someAlmondButter;
@Inject
AlmondButter otherAlmondButter;

这将创建两个单独的AlmondButter个实例。这是一个微不足道的案例,但希望它说明了每次请求依赖项时都会创建一个新的。

想象一下,现在你有两个不同的类,每个类都有一个字段@Inject AlmondButter sharedAlmondButter。如果您希望它们具有相同的实例,则范围将为您处理。

同样,如果您拥有任何依赖关系,则可以注入Provider<T>,即@Inject Provider<AlmondButter> almondButterProvider。这可以让您调用almondButterProvider.get()来检索新实例。如果您希望.get()返回的所有值都是同一个实例,则范围将完成相同的操作。