Dagger2 what is the purpose of adding a scope tag

2019-09-12 23:02发布

I've created a component and it only last for the lifetime of the activity. I did not use any scope annotations and only quick example of the life time of the component looks like this:

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

}

none of my components are scoped with anotations and it works fine. So im confused why some recommend to create scope tags, what is there purpose ? i'll show you my components below for reference:

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

and the next component:

    @Component(modules={ButterModule.class})

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

UPDATE: FOR ANYONE WHO NEEDS HELP WITH UNDERSTANDING THESE CONCEPTS I MADE A BLOG HERE.

2条回答
Evening l夕情丶
2楼-- · 2019-09-12 23:49

By using scopes on component and scopes on module provider method, you can ask Dagger2 to create scoped providers for you.

In order to get a scoped provider in your module's provider method, you must put the scope on the component as well.

You can specify only one scope on a given component, and in a scoped component, you can only have modules with that scope on its provider methods, or the provider methods can also be unscoped.

Unscoped providers give you a new instance on every inject call. Scoped providers store a single instance for every inject call to that specific component instance.

@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
}

It is also worth noting that if you subscope another component to inherit its dependencies (using subcomponent or component dependency), you can only depend on one other scoped component. Think of it like how "multiple inheritance" is not allowed in Java, you also cannot depend on multiple scoped components and inherit their dependencies, only one.

Typically you have a singleton scope, and you subscope your components according to the top-level separation of modules in your application.

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

According to 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).

查看更多
闹够了就滚
3楼-- · 2019-09-13 00:02

Scopes manage the instance creation across multiple requests for the same type. Imagine if you had this:

@Inject
AlmondButter someAlmondButter;
@Inject
AlmondButter otherAlmondButter;

This would create two separate AlmondButter instances. A trivial case, but hopefully it illustrates the point that each time you request the dependency, a new one is created.

Imagine now you have two different classes, each with a field @Inject AlmondButter sharedAlmondButter. If you want them to have the same exact instance, a scope will handle that for you.

Similarly, with any dependency you have, you can inject a Provider<T>, i.e. @Inject Provider<AlmondButter> almondButterProvider. This can allow you to call almondButterProvider.get() to retrieve a new instance. If you then wanted all values returned by .get() to be the same instance, a scope would accomplish the same thing.

查看更多
登录 后发表回答