我和 Dagger2共事有一段时间了。我不知道是否应该为每个活动/片段创建一个自己的组件/模块。请帮我澄清一下:
例如,我们有一个应用程序,这个应用程序有大约50个屏幕。 我们将按照 MVP 模式和 Dagger2实现 DI 的代码。假设我们有50个活动和50个演讲者。
在我看来,通常我们应该这样组织代码:
创建一个 AppComponent 和 AppModule,它将提供在应用程序打开时使用的所有对象。
@Module
public class AppModule {
private final MyApplicationClass application;
public AppModule(MyApplicationClass application) {
this.application = application;
}
@Provides
@Singleton
Context provideApplicationContext() {
return this.application;
}
//... and many other providers
}
@Singleton
@Component( modules = { AppModule.class } )
public interface AppComponent {
Context getAppContext();
Activity1Component plus(Activity1Module module);
Activity2Component plus(Activity2Module module);
//... plus 48 methods for 48 other activities. Suppose that we don't have any other Scope (like UserScope after user login, ....)
}
Create ActivityScope :
@Scope
@Documented
@Retention(value=RUNTIME)
public @interface ActivityScope {
}
Create Component and Module for each Activity. Usually I will put them as static classes within the Activity class:
@Module
public class Activity1Module {
public LoginModule() {
}
@Provides
@ActivityScope
Activity1Presenter provideActivity1Presenter(Context context, /*...some other params*/){
return new Activity1PresenterImpl(context, /*...some other params*/);
}
}
@ActivityScope
@Subcomponent( modules = { Activity1Module.class } )
public interface Activity1Component {
void inject(Activity1 activity); // inject Presenter to the Activity
}
// .... Same with 49 remaining modules and components.
Those are just very simple examples to show how I would implement this.
But a friend of mine just gave me another implementation:
Create PresenterModule which will provide all presenters:
@Module
public class AppPresenterModule {
@Provides
Activity1Presenter provideActivity1Presentor(Context context, /*...some other params*/){
return new Activity1PresenterImpl(context, /*...some other params*/);
}
@Provides
Activity2Presenter provideActivity2Presentor(Context context, /*...some other params*/){
return new Activity2PresenterImpl(context, /*...some other params*/);
}
//... same with 48 other presenters.
}
Create AppModule and AppComponent:
@Module
public class AppModule {
private final MyApplicationClass application;
public AppModule(MyApplicationClass application) {
this.application = application;
}
@Provides
@Singleton
Context provideApplicationContext() {
return this.application;
}
//... and many other provides
}
@Singleton
@Component(
modules = { AppModule.class, AppPresenterModule.class }
)
public interface AppComponent {
Context getAppContext();
public void inject(Activity1 activity);
public void inject(Activity2 activity);
//... and 48 other methods for 48 other activities. Suppose that we don't have any other Scope (like UserScope after user login, ....)
}
His explaination is: He doesn't have to create components and modules for each activity. I think my friends idea is absolutely not good at all, but please correct me if I am wrong. Here are the reasons:
A lot of memory leaks :
What happens if I want to create two instances of one Activity ? (how can he create two presenters )
It will take a lot of time for the app to initialize (because it has to create many presenters, objects, ...)
Sorry for a long post, but please help me clarify this for me and my friend, I can't convince him. Your comments will be very appreciated.
/-----------------------------------------------------------------------/
Edit after doing a demo.
First, thanks for @pandawarrior answer. I should have created a Demo before I asked this question. I hope my conclusion here could help someone else.
So, all the reasons I have said above are mostly wrong. But it does not mean that we should follow my friend idea, for two reasons:
It's not good for the source's architecture, when he inits all presenters in module / component. (It violates Interface segregation principle, maybe Single Responsibility priciple, too).
When we create a Scope Component, we will know when it's created and when it's destroyed which is a huge benefit for avoiding memory leaks. So, for each Activity we should create a Component with an @ActivityScope. Let's imagine, with my friends implementation, that we forgot to put some Scope in the Provider-method => memory leaks will occur.
In my opinion, with a small app (just a few screens without many dependencies or with similar dependencies), we could apply my friends idea, but of course it's not recommended.
Prefer to read more on: What determines the lifecycle of a component (object graph) in Dagger 2? Dagger2 activity scope, how many modules/components do i need?
And one more note: If you want to see when the object are destroyed, you can call those of method together and the GC will run immediately:
System.runFinalization();
System.gc();
如果你只使用这些方法中的一种,GC 会运行得更晚,你可能会得到错误的结果。