Dagger - 在不同的组件上获取相同的实例

Dagger - Getting Same Instance On Different Component

我遇到了与 问题类似的问题。 虽然接受的答案确实有帮助,但我缺少解决问题的最后一部分。

我有 2 个 android 库模块:commonexp 这取决于 common.

common下的所有内容:

@Module
public class CommonModule {
    @Singleton
    @Provides
    public Repository providesRepository() {
        return new Repository();
    }
}

@Singleton
@Component(modules={CommonModule.class})
public interface CommonComponent {
    void inject(CommonClass commonClass);
    /**
        CommonClass needs instance of Repository
    **/
}

public class CommonDIHolder {
    public static CommonComponent sComponent;

    public static void init() {
        sComponent = DaggerCommonComponent.builder().build();
    }
}

exp下的所有内容:

@Module(includes={CommonModule.class})
public class ExpModule {
    @Singleton
    @Provides
    public ExpResource provideExpResource() {
        return new ExpResource();
    }
}

@Singleton
@Component(modules={ExpModule.class}, dependencies={CommonComponent.class})
public interface ExpComponent {
    void inject(ExpClass expClass); 
    /**
        ExpClass needs instance of Repository and ExpResource
    **/
}

public class ExpDIHolder {
    public static ExpComponent sComponent;

    public static void init() {
        sComponent = DaggerExpComponent.builder()
                            .commonComponent(CommonDIHolder.sComponent)
                            .build();
    }
}

我需要 CommonClassExpClass 接收相同的 Repository 实例。

这种方法的问题是 @Singleton 不能依赖于 @Singleton。所以我必须将 ExpComponent 的范围更改为名为 @ExpScope 的自定义范围。然后我也将 provideExpResource 更改为 @ExpScope

然后我遇到一个错误,说 ExpComponent 可能不会引用不同范围的绑定。它指的是 provideRepository 具有不同的范围 (@Singleton)。如果我将范围更改为 ExpScope,那么 CommonComponent 将具有与 provideRepository 不同的范围。

如果我将所有 @Singleton 更改为 @ExpScope,那么我会收到此错误消息:depends on scoped components in a non-hierarchical scope ordering

我该怎么办?或者我在这里做错了方法?

只使用一个 @Singleton 作用域组件

你应该有一个并且只有一个 @Singleton 作用域组件是这样的:

@Singleton
@Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {

}

仅指定活动、片段和服务作为组件的显式注入目标

在 Android 应用程序中,您应该只将 Activity、Fragments 和 Services 列为注入站点。您应该配置 Dagger 2 以注入其余的依赖项,而不必诉诸于在它们内部调用 component.inject(this)

例如,如果您的 CommonClass 看起来像这样:

public class CommonClass {
    @Inject Repository repository;

    public class CommonClass() {
         CommonComponentHolder.get().inject(this);
    }
}

重构如下:

public class CommonClass {
    private final Repository repository;

    @Inject
    public class CommonClass(Repository repository) {
         this.repository = repository;
    }
}

现在,当您有一个 Activity 或需要 CommonClass 的片段并且您正在注入 CommonComponent 或其子组件或依赖组件之一时,它们可以获得实例CommonClass 连接了正确的依赖项:

public class MyActivity extends AppCompatActivity {

    @Inject CommonClass commonClass;

    public void onCreate(Bundle savedInstanceState) {
        CommonComponentHolder.getComponent().inject(this);
    }
}

使用子组件或依赖组件指定注入目标

现在您有一个 @Singleton 范围的组件,您可能想要为您的 Activity 或 Fragment 创建一个范围更窄的组件。您必须将它连接到您的 CommonComponent,因此使用依赖组件或子组件(从 Dagger 2.10 开始首选子组件)。既然你说你已经尝试过定义一个 @ExpScope,我认为缺少的部分是使用注入你的 Activity 或片段的 @ExpScope 制作子组件或依赖组件。

顶级单例组件类似于以下内容:

@Singleton
@Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
    ExpComponent.Builder exComponent();
}

然后对于子组件:

@ExpScope
@Subcomponent(modules = {NarrowerScopedModule.class})
public interface ExpComponent {
    @Subcomponent.Builder
    public interface Builder {
        Builder narrowerScopedModule(NarrowerScopedModule narrowerScopedModule);
        ExpComponent build();
    }
}

Google Android Architecture Blueprints Github repo

中有 Android 个项目的良好工作示例