Dagger: How can I create only one instance of object for each sub component ?

Created on 15 Feb 2018  ·  20Comments  ·  Source: google/dagger

How can I create only one instance of object for each sub component ?
I use dagger android, I have this scopes
AppScope
ActiivtyScope
FragmentScope
Lets say I have an activity with two fragments, how can I create a new instance of X object for my Activity and for each of fragments separately ?

Most helpful comment

it's Ok,
Thank you
I solve the issue, and put the fragmens and activities under one single scope, @screen scope, and they are both subcomponents for the @AppScope

All 20 comments

I'm not familiar with them, but maybe @Reusable scope?

The @Reusable scope will create instance of X object for @AppScope and provide the same instance for @ActivityScope and for @FragmentScope, seance they are Sub Component scopes ( AppComponent -> XActivitySubComponent -> XFragmentSubcomponent ), I mean the same instance will be injected for Activity and Fragment, @Reusable is not solve the problem, thanks for answer

If you define your own scope and apply it to a subcomponent, any binding with that scope will achieve what you're searching to do.

Example:

@Scope
@interface RobertScope {}

@RobertScope
@Subcomponent(modules = RobertModule.class)
interface ActivitySubcomponent {
  ActivityScopedObject a();
}

@Module
class RobertModule {
  @Provides
  @RobertScope
  ActivityScopedObject a() {
   return ... 
  }
}

@tbroyer @Reusable _may_ be shifted down the component tree if it is unused in the parent that defines it, but if you _need_ specific characteristics, a regular scope is the way to go.

Thanks for answer

But I think you got my question wrong, let me formulate it in another way:

I want to create and reuse the created instances in each sub component, for more details please see attached image, thank you in advance for you feedback

image

Yup, that's what happens. Every time a new instance of a component is created, it has it's own new set of scoped bindings.

But in this case what is my instance's scope ?

  1. if it is annotated with @FragmentScope the compilation will fail, because my activity is in the @ActivityScope but the instance I want to inject is annotates @FragmentScope).
  2. if the instance is annotated with @ActivityScope
    , than it will be shared for Fragment1 and Fragment2, since they are sub components for activity component

Oh, you want _one_ binding that will have a separate instance for each of them? There's no built-in way to do that.

You could probably hack something together with Map multibindings, i.e. Map<Class<? extends Annotation> /* scope class */, YourBinding> if you want.

Yes, you understand the issue correctly, I solve the issue, and put the fragmens and activities under one single scope, @Screen scope, and they are both subcomponents for the @AppScope

@RobertApikyan

Have you tried composing your objects? Based on your scope hierarchy.

Yes, Shure. But I need to bind a new object to every sub scope, this I think is an injection pattern

Not sure if I understand totally...

This is what I mean, at least one way of doing it.

abstract class BaseType<T extends BaseType> {
  final T type;

  BaseType(T type){ this.type = type; }
}

@AppScope class AppType extends BaseType {
  @Inject AppType(){  super(null); }

  void appThing(){}
}

@ActivityScope class ActivityType extends BaseType<AppType> {
  @Inject ActivityType(AppType type){ super(type); }

  void appThing(){ type.appThing(); }

  void activityThing(){}
}

@FragmentScope class FragmentType extends BaseType<ActivityType> {
  @Inject FragmentType(ActivityType type){ super(type); }

  void appThing(){ type.appThing(); }

  void activityThing(){ type.activityThing(); }

  void fragmentThing(){}
}

Probably more then you would want to do. But it's not too bad as long as you don't have a large amount of scopes.

thanks for the example,
But I think you got my question wrong.
Imagine the situation when my activityComponent (@ActivityScope) is subcomponent for the appComponent(@AppScope) and the fragmentComponent(@FragmentScope) is the subComponent for the activityComponent.
I have an HomeActivity which contains two fragments, with specified scopes ( StatisticsFragment and the RequestsFragment)
Now I need to create a new instance of some object (lets call it X object) one for my HomeActivity, one for StatisticsFragment and one for RequestsFragment and reuse thins objects, I mean if I already have created this object for my RequestsFragment I want to reuse it for RequestsFragmentPresenter and for RequestsRepository, and the same behevior for HomeActivity and StatisticsFragment.
Now the problem is that when I create the instance of X object for my HomeActivity, it passes the same created object from HomeActiviy to RequestsFragment and StatisticsFragment.

  1. if X is annotated with @FragmentScope the compilation will fail, because my activity is in the @ActivityScope but the instance I want to inject is annotates @FragmentScope).
  2. if the X instance is annotated with @ActivityScope
    , than it will be shared for Fragment1 and Fragment2, since they are sub components for activity component

You can see the diagram here

image

Ah, I think I understand now. Actually sounds like it's more of an Activity/Fragment lifecycle issue, not injection.

I'm guessing you'd want the object cleared when its supplying activity or fragment is destroyed etc...

Not so close, the issue is to create new Instance of X object once for every sub scope, and reuse the instance in its scope, for HomeActivity and for 2 child fragments I need 3 new instances of X object

Sorry I couldn't help.

I hope you get something figured out.

it's Ok,
Thank you
I solve the issue, and put the fragmens and activities under one single scope, @screen scope, and they are both subcomponents for the @AppScope

@RobertApikyan Hello Robert, I'm stuck in the same problem you had before so please can you tell me in details how you managed it ?

Hi, sorry for late answer ... 

Вторник, 30 апреля 2019, 21:53 +04:00 от Hasan Badran notifications@github.com:

@RobertApikyan Hello Robert, I'm stuck in the same problem you had before so please can you tell me in details how you managed it ?

You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub , or mute the thread .

С уважением,
Robert Apikyan
[email protected]

If you want to have different instances in the Component and in it's Sub-components, The problem can not be resolved, dagger do not support such a dependency schema, 

I have crated the custom Scope ( @ScreenScope ) and applied it to my activity and to it's child fragments, so now the activity and it's child fragments do not share any objects, 
not a perfect solution it, but this was the only one for that time ... To be honest now i'm trying to avoid using of dagger in my projects, overall it's a good library,  but in this common case it does not provide valid solution ... 

Четверг, 2 мая 2019, 13:19 +04:00 от Robert Apikyan robertapikyan@mail.ru:

Hi, sorry for late answer ... 

Вторник, 30 апреля 2019, 21:53 +04:00 от Hasan Badran < [email protected] >:

@RobertApikyan Hello Robert, I'm stuck in the same problem you had before so please can you tell me in details how you managed it ?

You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub , or mute the thread .

С уважением,
Robert Apikyan
[email protected]

С уважением,
Robert Apikyan
[email protected]

@RobertApikyan Thanks man!

Was this page helpful?
0 / 5 - 0 ratings