gpt4 book ai didi

android - Dagger- 我们应该为每个 Activity/fragment 创建每个组件和模块吗?

转载 作者:IT老高 更新时间:2023-10-28 13:10:28 25 4
gpt4 key购买 nike

我使用 dagger2 已经有一段时间了。我对为每个 Activity/fragment 创建自己的组件/模块感到困惑。请帮我澄清一下:

例如,我们有一个应用程序,该应用程序大约有 50 个屏幕。
我们将按照 MVP 模式和 Dagger2 为 DI 实现代码。假设我们有 50 个 Activity 和 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, ....)

    }
  • 创建 Activity 范围:
    @Scope
    @Documented
    @Retention(value=RUNTIME)
    public @interface ActivityScope {
    }
  • 为每个 Activity 创建组件和模块。通常我会将它们作为静态类放在 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.

  • 这些只是非常简单的例子来展示我将如何实现这一点。

    但是我的一个 friend 刚刚给了我另一个实现:
  • 创建 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, ....)

    }

  • 他的解释是: 他不必为每个 Activity 创建组件和模块。
    我觉得我 friend 的想法绝对不好,但如果我错了,请纠正我。原因如下:
  • 大量内存泄漏 :
  • 即使用户只打开了 2 个 Activity ,该应用程序也会创建 50 个演示者。
  • 用户关闭一个 Activity 后,它的 Presenter 仍然是
  • 如果我想创建一个 Activity 的两个实例会发生什么? (他怎么能创建两个演示者)
  • 应用程序初始化需要很多时间(因为它必须创建许多演示者、对象……)

  • 很抱歉发表了很长的帖子,但请帮我为我和我的 friend 澄清这一点,我无法说服他。
    您的意见将不胜感激。

    /------------------------------------------------- ---------------/

    做一个演示后编辑。

    首先,感谢@pandawarrior 的回答。
    在问这个问题之前,我应该创建一个演示。我希望我在这里的结论可以帮助别人。
  • 我的 friend 所做的不会导致内存泄漏,除非他将任何 Scope 放入 Provides-methods。 (例如@Singleton,或@UserScope,...)
  • 如果提供方法没有任何范围,我们可以创建许多演示者。 (所以,我的第二点也错了)
  • Dagger 只会在需要时创建演示者。 (所以,应用程序不会花很长时间初始化,我被懒惰的注入(inject)搞糊涂了)

  • 所以,我上面说的所有理由大多是错误的。但这并不意味着我们应该遵循我 friend 的想法,原因有二:
  • 当他在模块/组件中初始化所有演示者时,这对源的架构不利。 (它也违反了 Interface segregation principle ,也可能违反了 Single Responsibility 原则)。
  • 当我们创建一个 Scope 组件时,我们会知道它什么时候创建,什么时候销毁,这对于避免内存泄漏是一个巨大的好处。因此,对于每个 Activity,我们应该创建一个带有 @ActivityScope 的组件。让我们想象一下,在我 friend 的实现中,我们忘记在 Provider-method 中放置一些 Scope => 会发生内存泄漏。

  • 在我看来,用一个小应用程序(只有几个屏幕,没有很多依赖或类似的依赖),我们可以应用我 friend 的想法,但当然不推荐。

    更喜欢阅读以下内容:
    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 会运行得更晚,你可能会得到错误的结果。

    最佳答案

    为每个 Activity 声明一个单独的模块根本不是一个好主意。为每个 Activity 声明单独的组件更糟。这背后的原因很简单——您并不真正需要所有这些模块/组件(正如您自己已经看到的那样)。

    但是,只有一个与 Application 相关联的组件的生命周期并将其用于注入(inject)所有 Activities也不是最佳解决方案(这是您 friend 的方法)。它不是最佳的,因为:

  • 它限制你只有一个范围( @Singleton 或自定义范围)
  • 您被限制的唯一范围使注入(inject)的对象成为“应用程序单例”,因此范围对象的错误使用或不正确的使用很容易导致全局内存泄漏
  • 您需要使用 Dagger2 来注入(inject) Services也是,但是 Services可以需要与 Activities 不同的对象(例如 Services 不需要演示者,不需要 FragmentManager 等)。通过使用单个组件,您失去了为不同组件定义不同对象图的灵活性。

  • 因此,每个 Activity 的一个组件是一种矫枉过正,但整个应用程序的单个组件不够灵活。最佳解决方案介于这些极端之间(通常如此)。

    我使用以下方法:
  • 提供“全局”对象的单个“应用程序”组件(例如,保存在应用程序中所有组件之间共享的全局状态的对象)。实例化于 Application .
  • “应用程序”组件的“ Controller ”子组件提供所有面向用户的“ Controller ”所​​需的对象(在我的架构中,这些是 ActivitiesFragments )。在每个 Activity 中实例化和 Fragment .
  • “应用程序”组件的“服务”子组件,提供所有 Services 所需的对象.在每个 Service 中实例化.

  • 以下是如何实现相同方法的示例。

    2017 年 7 月编辑

    我发布了一个视频教程,展示了如何在 Android 应用程序中构建 Dagger 依赖注入(inject)代码: Android Dagger for Professionals Tutorial .

    2018 年 2 月编辑

    我发表了一篇 complete course about dependency injection in Android .

    在本类(class)中,我解释了依赖注入(inject)的理论,并展示了它是如何在 Android 应用程序中自然出现的。然后我演示了 Dagger 构造如何适应一般的依赖注入(inject)方案。

    如果您参加本类(class),您将理解为什么为每个 Activity/fragment 单独定义模块/组件的想法在最基本的方面基本上是有缺陷的。

    这种方法使表示层的结构从“功能”类集合镜像到“构造”类集合结构,从而将它们耦合在一起。这违背了依赖注入(inject)的主要目标,即保持类的“构造”和“功能”集不相交。

    适用范围:
    @ApplicationScope
    @Component(modules = ApplicationModule.class)
    public interface ApplicationComponent {

    // Each subcomponent can depend on more than one module
    ControllerComponent newControllerComponent(ControllerModule module);
    ServiceComponent newServiceComponent(ServiceModule module);

    }


    @Module
    public class ApplicationModule {

    private final Application mApplication;

    public ApplicationModule(Application application) {
    mApplication = application;
    }

    @Provides
    @ApplicationScope
    Application applicationContext() {
    return mApplication;
    }

    @Provides
    @ApplicationScope
    SharedPreferences sharedPreferences() {
    return mApplication.getSharedPreferences(Constants.PREFERENCES_FILE, Context.MODE_PRIVATE);
    }

    @Provides
    @ApplicationScope
    SettingsManager settingsManager(SharedPreferences sharedPreferences) {
    return new SettingsManager(sharedPreferences);
    }
    }

    Controller 范围:
    @ControllerScope
    @Subcomponent(modules = {ControllerModule.class})
    public interface ControllerComponent {

    void inject(CustomActivity customActivity); // add more activities if needed

    void inject(CustomFragment customFragment); // add more fragments if needed

    void inject(CustomDialogFragment customDialogFragment); // add more dialogs if needed

    }



    @Module
    public class ControllerModule {

    private Activity mActivity;
    private FragmentManager mFragmentManager;

    public ControllerModule(Activity activity, FragmentManager fragmentManager) {
    mActivity = activity;
    mFragmentManager = fragmentManager;
    }

    @Provides
    @ControllerScope
    Context context() {
    return mActivity;
    }

    @Provides
    @ControllerScope
    Activity activity() {
    return mActivity;
    }

    @Provides
    @ControllerScope
    DialogsManager dialogsManager(FragmentManager fragmentManager) {
    return new DialogsManager(fragmentManager);
    }

    // @Provides for presenters can be declared here, or in a standalone PresentersModule (which is better)
    }

    然后在 Activity :
    public class CustomActivity extends AppCompatActivity {

    @Inject DialogsManager mDialogsManager;

    private ControllerComponent mControllerComponent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getControllerComponent().inject(this);

    }

    private ControllerComponent getControllerComponent() {
    if (mControllerComponent == null) {

    mControllerComponent = ((MyApplication)getApplication()).getApplicationComponent()
    .newControllerComponent(new ControllerModule(this, getSupportFragmentManager()));
    }

    return mControllerComponent;
    }
    }

    关于依赖注入(inject)的附加信息:

    Dagger 2 Scopes Demystified

    Dependency Injection in Android

    关于android - Dagger- 我们应该为每个 Activity/fragment 创建每个组件和模块吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36206989/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com