问题
I'm having a similar problem like the one in this question. While the accepted answer does help, but I'm missing final piece to solve the problem.
I have 2 android library modules: common
and exp
which depends on common
.
Everything under common
:
@Module
public class CommonModule {
@Singleton
@Provides
public Repository providesRepository() {
return new Repository();
}
}
@Singleton
@Component(modules={CommonModule.class})
public interface CommonComponent {
void inject(CommonClass commonClass);
/**
CommonClass needs instance of Repository
**/
}
public class CommonDIHolder {
public static CommonComponent sComponent;
public static void init() {
sComponent = DaggerCommonComponent.builder().build();
}
}
Everything under exp
:
@Module(includes={CommonModule.class})
public class ExpModule {
@Singleton
@Provides
public ExpResource provideExpResource() {
return new ExpResource();
}
}
@Singleton
@Component(modules={ExpModule.class}, dependencies={CommonComponent.class})
public interface ExpComponent {
void inject(ExpClass expClass);
/**
ExpClass needs instance of Repository and ExpResource
**/
}
public class ExpDIHolder {
public static ExpComponent sComponent;
public static void init() {
sComponent = DaggerExpComponent.builder()
.commonComponent(CommonDIHolder.sComponent)
.build();
}
}
I need both CommonClass
and ExpClass
receive the same instance of Repository
.
The problem with this approach is that @Singleton
can't depends on @Singleton
. So I have to change the scope of ExpComponent
into self-defined scope called @ExpScope
. Then I changed the provideExpResource
into @ExpScope
as well.
Then I encountered an error saying that ExpComponent
may not reference bindings with different scopes. It refers to the provideRepository
which has different scope (@Singleton
) on it. If I changed the scope into ExpScope
then the CommonComponent
will have different scope with provideRepository
.
If I changed all @Singleton
into @ExpScope
then I receive this error message: depends on scoped components in a non-hierarchical scope ordering
What should I do? Or I'm doing the wrong approach here?
回答1:
Use one and only one @Singleton
scoped component
You should have one and only one @Singleton
scoped component like this:
@Singleton
@Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
}
Only specify Activities, Fragments, and Services as explicit injection targets for Components
In an Android app, you should only list Activities, Fragments and Services as injection sites. You should configure Dagger 2 to inject the rest of your dependencies without having to resort to calling component.inject(this)
inside them.
For example, if your CommonClass
looks like this:
public class CommonClass {
@Inject Repository repository;
public class CommonClass() {
CommonComponentHolder.get().inject(this);
}
}
Refactor it like this:
public class CommonClass {
private final Repository repository;
@Inject
public class CommonClass(Repository repository) {
this.repository = repository;
}
}
Now when you have an Activity or Fragment that needs CommonClass
and you are injecting with CommonComponent
or one of its sub-components or dependent components, they can obtain instances of CommonClass
wired with the correct dependencies:
public class MyActivity extends AppCompatActivity {
@Inject CommonClass commonClass;
public void onCreate(Bundle savedInstanceState) {
CommonComponentHolder.getComponent().inject(this);
}
}
Use subcomponents or dependent components to specify the injection targets
Now you have a @Singleton
scoped component, you'll probably want to create a component for a narrower scope for your Activity or Fragment. You'll have to connect it to your CommonComponent
, so use dependent components or subcomponents (subcomponents are preferred as of Dagger 2.10). Since you say you have already tried defining a @ExpScope
, I think the missing piece is to make subcomponent or dependent component with the @ExpScope
that injects your Activity or Fragment.
Something like the following for the top-level singleton component:
@Singleton
@Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
ExpComponent.Builder exComponent();
}
And then for the subcomponent:
@ExpScope
@Subcomponent(modules = {NarrowerScopedModule.class})
public interface ExpComponent {
@Subcomponent.Builder
public interface Builder {
Builder narrowerScopedModule(NarrowerScopedModule narrowerScopedModule);
ExpComponent build();
}
}
There are good working examples of Android projects in the Google Android Architecture Blueprints Github repo
来源:https://stackoverflow.com/questions/42953373/dagger-getting-same-instance-on-different-component