当前位置: 首页 > 面试题库 >

如何告诉Dagger 2基于X实例化哪个实现?

闾丘朗
2023-03-14
问题内容

在模块内部,如果需要基于模块构造时已知的变量提供不同的接口实现,则可以将逻辑放入该接口类型的@Provides方法中。像这样:

    @Module
    public class FooModule {

        private final State state;

        public FooModule(State state) {
            this.state = state;
        }

        @Provides
        FooInterface provideFooImplementation() {
            switch(state) {
                case STATE_1:
                    return new FooImpl1();
                case STATE_2:
                    return new FooImpl2();
                ...
                case STATE_10:
                    return new FooImpl10();
            }
        }
    }

但是,这些实现可以由Dagger创建。我宁愿说“嘿,基于XI希望您为我实例化此类”

我考虑了几种选择。

  1. 更改providers方法以采用所有可能的实现:
        @Provides
    FooInterface provideFooImplementation(FooImpl1 impl1, FooImpl2 imp2, ..., FooImpl10 impl10) {
        switch(state) {
            case STATE_1:
                return impl1;
            case STATE_2:
                return impl2;
            ...
            case STATE_10:
                return impl10;
        }
    }

这允许Dagger实例化它们并满足它们的所有依赖关系,但是如果每个实现都相对较大或创建成本很高,则不是一个好主意。

  1. 更改Provides方法以获取不同实现的所有依赖项的集合。
        @Provides
    FooInterface provideFooImplementation(Context context, Repo repo, HttpClient httpClient, ...) {
        switch(state) {
            case STATE_1:
                return new FooImpl1(context);
            case STATE_2:
                return new FooImpl2(repo, httpClient);
            ...
            case STATE_10:
                return new FooImpl10(context, repo);
        }
    }

这比选项1稍好一点,因为Dagger不必实例化每个单个实现,但是,即使可能并非在所有情况下都使用它们,它仍然需要实例化所有依赖关系。我也要自己创建对象,即使它们可以由Dagger创建。

  1. 每个实现创建一个模块,并实例化适当的模块。所以像这样:
        @Module
    public FooImpl1Module {

        @Provides
        FooInterface provideFooImplementation(Context context) {
            return new FooImpl1(context);
        }
    }

很好,但是现在我在定义依赖于模块的组件时遇到了问题。

解决这个问题的最佳方法是什么?

一种建议是尝试使用包裹在Lazy中的参数的选项1。然后,我最终只对其中一个调用.get()。我会尽可能尝试并发布结果


问题答案:

而不是使用Lazy<T>选项1
Provider<T>Lazy<T>只是一个Provider<T>在本地存储的(具有必要的双重检查锁定),但是由于您仅会一次调用一个提供程序,因此您可以注入该提供程序,而跳过同步开销。

    @Provides
    FooInterface provideFooImplementation(
            Provider<FooImpl1> impl1,
            Provider<FooImpl2> impl2,
            ...,
            Provider<FooImpl10> impl10) {
        switch(state) {
            case STATE_1:
                return impl1.get();
            case STATE_2:
                return impl2.get();
            ...
            case STATE_10:
                return impl10.get();
        }
    }

选项2可以使用,但是您将有效地跳过Dagger可以轻松为您完成的依赖关系,并且选项3不能按所述方式运行,因为@Component批注需要模块列表作为您的编译时常量。
Dagger代码生成可以正常工作。

(如果绑定是绑定到一种形式或另一种形式的常数或零依赖性类,则选项3的变体可以工作,因为这样您就可以将Module的任意子类传递到Component
builder中。但是,Dagger只能分析如果您的@Provides方法实现采用的参数与您使用的参数不同,那么您将遇到麻烦,因此,这switch是我能想到的最好,最清晰的替代方法。)



 类似资料:
  • 我是使用Dagger2的新手(我一直使用Koin),我正在尝试实现一个简单的示例,但我真的不知道我缺少了什么。这就是我目前得到的。 app.gradle: 应用模块。kt: AppComponent。kt: TestClass。千吨 pp.kt: MainActivity.kt: 错误:testClass==null

  • 我的项目有多个具有方法的类。如何告诉Spring Boot Maven插件应该使用哪个类作为主类?

  • 本文向大家介绍基于spring如何实现事件驱动实例代码,包括了基于spring如何实现事件驱动实例代码的使用技巧和注意事项,需要的朋友参考一下 干货点 通过阅读该篇博客,你可以了解了解java的反射机制、可以了解如何基于spring生命周期使用自定义注解解决日常研发问题。具体源码可以点击链接。 问题描述 在日常研发中,经常会遇见业务A的某个action被触发后,同时触发业务B的action的行为,

  • 我使用Spock进行测试,我有多个类要测试。我想告诉Spock按照特定的顺序测试每个类。有办法做到这一点吗?我注意到TestNG有注释,那么Spock也有类似的注释吗?

  • 我使用和将日期字符串从1970年起传递到毫秒。 问题是日期字符串上不包含时区。他们是英国人,所以时区将是GMT或GMT+1取决于日期... 当我在前端(Chrome)或后端(Node.js)中使用此技术时。所取时区为英国时区(GMT或GMT+1,视日期而定)。我认为这是从操作系统中提取的。 但是,在使用Node.js服务器时,我被告知该服务器配置为UTC格式...时区总是格林尼治标准时间,导致英国

  • 我正在为Eclipse Juno编写一个插件,我想使用类AbstractSourceLookupDirector。当我查看API时,它说它有一个构造函数,但是当我在代码中使用以下语句时,它说“不能实例化类型AbstractSourceLookupDirector” AbstractSourceLookupDirector srclookupDir=新的AbstractSourceLookupDir