【问题标题】:one object if injected into 2 subcomponents under same custom scope, every time new instance is created of that object如果将一个对象注入到同一自定义范围下的 2 个子组件中,则每次创建该对象的新实例时
【发布时间】:2018-09-11 10:37:51
【问题描述】:

一个对象如果注入到相同自定义范围下的 2 个子组件中,则每次创建该对象的新实例时。我希望将相同的实例传递给所有子组件

这是模块

@CustomScope
@Module
public class EventBusModule {

    PublishSubject<Boolean> bus = PublishSubject.create();

    @CustomScope
    @Provides
    public PublishSubject<Boolean> provideRxBus() {
        return bus;
    }
}

这些是我的子组件

@Module
public abstract class ActivityBindingModule {

    @CustomScope
    @ContributesAndroidInjector(modules = {HomeActivityModule.class, 
    EwayBillFragmentProvider.class, EventBusModule.class})
    abstract HomeActivity mainActivity();

    @CustomScope
    @ContributesAndroidInjector(modules = 
    {EwayBillDetailActivityModule.class, EventBusModule.class})
    abstract EwayBillDetailActivity ewayBillDetailActivity();
}

这些子组件写在 ActivityBindingModule 中,它被添加到我的应用程序组件中。现在我想要两个子组件中的 PublishSubject 对象的相同实例,我对 dagger 还很陌生,我想知道我做错了什么?

【问题讨论】:

    标签: android dependency-injection dagger-2 custom-scope subcomponent


    【解决方案1】:

    您需要将您的bus 移动到应用程序范围内,这通常意味着使用@Singleton 对其进行注释(如果这是您对安装了ActivityBindingModule 的顶级组件进行注释的方式)。您还需要将您的方法移动到安装在该组件上的模块中,这也可能是 ActivityBindingModule。

    @Module
    public abstract class ActivityBindingModule {
    
      @Singleton
      @Provides
      public PublishSubject<Boolean> provideRxBus() {
        // Dagger stores the instance in your Application component, so you don't have to.
        return PublishSubject.create();
      }
    
      /* ... your @ContributesAndroidInjector Activity bindings remain here ... */
    }
    

    首先,解释一下你所看到的: @ContributesAndroidInjector 为它所注解的每个对象创建一个子组件,用你在 @ContributesAndroidInjector 方法和注解上放置的范围注解和模块进行标记,所以您在 onCreate 中对 AndroidInjection.inject(this) 的调用会创建该子组件的新实例并使用它来注入 Activity 实例。

    @Provides PublishSubject&lt;Boolean&gt; 方法上的 @CustomScope(在此可以更好地命名为 @ActivityScope)意味着您的实例将与同样使用该范围注释进行注释的组件共享相同的生命周期。在这里,这是每个自动生成的子组件。此外,由于您的 Module 是具有公共无参数构造函数的 非抽象类,因此 Dagger 将在每次创建需要您的模块的 Component 时自动创建一个新实例,这意味着不同的 bus对于每个 Activity 实例。 (对于抽象类或接口的模块,它不能也不会这样做。)


    您希望您的 bus 对象在 Activity 之间是同一个实例,这意味着 @CustomScope/@ActivityScope 太短了:您希望该对象比任何单个 Activity 的生命周期都长。这意味着您需要将实例存储在其他位置并将其传递给每个 Activity,或者您需要将实例存储在应用程序组件本身中。我推荐后者,因为这是创建 Dagger 要解决的问题之一,并且因为这将自动使总线在您的应用程序中可用:Dagger 子组件继承对其父组件中所有绑定的访问。这给出了您在上面看到的代码。 (请注意,通过这样做,即使没有 Activity 显示,当您的应用程序在后台运行时,您也会保留 PublishSubject 的实例;如果您希望在 Activity 之间使用相同的实例,这是必要的结果,但是选择这要小心,以避免过多的后台内存使用。)

    另一种方法是您自己跟踪bus 实例,并将其插入到每个活动中。你可以通过让你的模块接受一个参数来做到这一点,但是that is rather tricky to do with dagger.android(它支持@ContributesAndroidInjector)。你也可以编写一个@Provides 方法来委托给一个WeakReference,或者使用上面的@Singleton 技术来编写一个在Activity 之间临时存储你的bus 的持有者。但是,由于 Android 对您在 Activity 和 Activity 生命周期之间的转换保留了很多控制权,因此您最好将bus 保留在@Singleton 范围内,就像我在上面的代码中所做的那样。

    【讨论】:

    • 感谢 Jeff 的精彩解释。听取您的建议就像一种魅力(公共汽车现在在应用范围内)。但是这个实验的目的是了解自定义范围(抱歉,之前应该提到过)。我想了解是否可以将相同的对象注入多个子组件但不是全部。
    • 这将帮助我决定我的应用程序应包含多少级组件层次结构。每个组件应该代表一个完整的功能(包含一些活动、片段、服务)还是应该是一个通用结构,应用程序级别位于最顶层,然后是所有活动(作为我的活动绑定模块中定义的不同子组件)片段可以是各个活动子组件的子组件,也可以是活动子组件中包含的模块。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多