我使用dagger2已经有一段时间了。而且我为每个活动/片段创建自己的组件/模块感到困惑。请帮我澄清一下:
例如,我们有一个应用程序,该应用程序有大约50个屏幕。我们将按照MVP模式和Dagger2 for 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, ....) }
创建ActivityScope:
@Scope @Documented @Retention(value=RUNTIME) public @interface ActivityScope { }
为每个活动创建组件和模块。通常,我会将它们作为静态类放入Activity类中:
@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.
这些只是非常简单的示例,以显示我将如何实现这一点。
但是我的一个朋友给了我另一个实现:
创建PresenterModule,它将提供所有演示者:
@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. }
创建AppModule和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, ....) }
他的解释是:他不必为每个活动创建组件和模块。 我认为我的朋友的想法绝对不好,但是如果我错了,请纠正我。原因如下:
很多内存泄漏:
- 即使用户仅打开两个活动,该应用程序仍将创建50个演示者。
- 用户关闭活动后,其演示者仍将保留
如果我想为一个活动创建两个实例,该怎么办?(他如何创建两个演示者)
应用初始化需要花费很多时间(因为它必须创建许多演示者,对象等)。
抱歉,很长的帖子,但是请帮助我为我和我的朋友澄清一下,我无法说服他。 您的意见将不胜感激。
/ ------------------------------------------------- ---------------------- /
演示后进行编辑。
首先,感谢@pandawarrior的回答。在问这个问题之前,我应该先创建一个演示。我希望我的结论可以对其他人有所帮助。
- 我的朋友所做的事情不会导致内存泄漏,除非他将任何范围都应用于Provides方法。(例如,@ Singleton或@UserScope,...)
- 如果Provides方法没有任何作用域,我们可以创建许多演示者。(所以,我的第二点也是错误的)
- Dagger仅在需要时创建演示者。(因此,该应用将不需要很长时间来初始化,我被懒惰注入所迷惑)
因此,我以上所述的所有原因大多都是错误的。但这并不意味着我们应该遵循我的朋友的想法,这有两个原因:
创建作用域组件时,我们将知道它的创建时间和销毁时间,这对于避免内存泄漏具有巨大的好处。因此,对于每个活动,我们都应该使用@ActivityScope创建一个组件。想象一下,在我的朋友实现中,我们忘记在Provider方法中放置一些Scope =>将会发生内存泄漏。
我认为,对于一个小型应用程序(只有几个没有很多依赖性或类似依赖性的屏幕),我们可以应用我的朋友的想法,但是当然不建议这样做。
首选阅读更多内容: 是什么决定了Dagger 2中组件(对象图)的生命周期? Dagger2活动范围,我需要多少个模块/组件?
还有一点要注意:如果要查看对象何时被销毁,可以一起调用方法的对象,GC将立即运行:
System.runFinalization();
System.gc();
如果仅使用这些方法之一,GC将在以后运行,并且可能会得到错误的结果。
ControllerModule
将创建一个新人Presenter
,然后将主持人插入Activity
或中Fragment
。任何赞成或反对的意见?