【发布时间】:2016-07-12 10:40:52
【问题描述】:
我使用 dagger2 已经有一段时间了。我很困惑是否为每个活动/片段创建自己的组件/模块。请帮我澄清一下:
例如,我们有一个应用程序,该应用程序有大约 50 个屏幕。 我们将按照 MVP 模式和适用于 DI 的 Dagger2 来实现代码。假设我们有 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, ....) } -
创建活动范围:
@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, ....) }
他的解释是:他不必为每个活动创建组件和模块。 我认为我朋友的想法绝对不好,但如果我错了,请纠正我。原因如下:
-
大量内存泄漏:
- 即使用户只打开了 2 个活动,该应用也会创建 50 个演示者。
- 用户关闭 Activity 后,其演示者仍将保留
如果我想创建一个 Activity 的两个实例会怎样? (他怎么能创建两个演示者)
应用初始化需要很长时间(因为它必须创建许多演示者、对象……)
很抱歉发了这么长的帖子,但请帮我为我和我的朋友澄清一下,我无法说服他。 您的 cmets 将不胜感激。
/------------------------------------------ ----------------------------------------/
进行演示后进行编辑。
首先,感谢@pandawarrior 的回答。 在我问这个问题之前,我应该创建一个演示。我希望我在这里的结论可以帮助其他人。
- 我的朋友所做的不会导致内存泄漏,除非他将任何 Scope 放入 Provides 方法。 (例如@Singleton 或@UserScope,...)
- 如果 Provides 方法没有任何范围,我们可以创建许多演示者。 (所以,我的第二点也是错误的)
- Dagger 只会在需要时创建演示者。 (所以,应用程序不会需要很长时间来初始化,我被惰性注入搞糊涂了)
所以,我上面所说的所有原因大多是错误的。但这并不意味着我们应该遵循我朋友的想法,原因有两个:
当他在模块/组件中初始化所有演示者时,这对源的架构不利。 (它违反了Interface segregation principle,也可能违反了Single Responsibility 原则)。
当我们创建一个作用域组件时,我们会知道它何时被创建以及何时被销毁,这对于避免内存泄漏是一个巨大的好处。因此,对于每个 Activity,我们应该创建一个带有 @ActivityScope 的组件。让我们想象一下,在我朋友的实现中,我们忘记在 Provider-method 中放置一些 Scope => 会发生内存泄漏。
在我看来,对于一个小应用程序(只有几个屏幕,没有很多依赖项或具有类似依赖项),我们可以应用我朋友的想法,但当然不推荐。
希望阅读更多内容: What determines the lifecycle of a component (object graph) in Dagger 2? Dagger2 activity scope, how many modules/components do i need?
还有一点需要注意:如果想查看对象什么时候被销毁,可以一起调用方法,GC会立即运行:
System.runFinalization();
System.gc();
如果您只使用其中一种方法,GC 将稍后运行,您可能会得到错误的结果。
【问题讨论】: