简体   繁体   English

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

[英]How do I tell Dagger 2 which implementation to instantiate based on X?

Inside a module, if I need to provide a different implementation of an interface based on a variable known at module construction time I can put the logic inside the @Provides method for that interface type. 在模块内部,如果我需要根据模块构造时已知的变量提供不同的接口实现,我可以将逻辑放在@Provides方法中用于该接口类型。 Like so: 像这样:

@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();
        }
    }
}

However, these implementations could be created by Dagger. 但是,这些实现可以由Dagger创建。 I would rather say "Hey, based on XI want you to instantiate this class for me" 我宁愿说“嘿,基于XI希望你为我实例化这个课程”

I have considered a couple of options. 我考虑了几个选择。

  1. Change the provides method to take in all of the possible implementations: 更改提供方法以接受所有可能的实现:

     @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; } } 

This allows Dagger to instantiate them and satisfy all of their dependencies but it's not a good idea if each of the implementations is relatively large or expensive to create. 这允许Dagger实例化它们并满足它们的所有依赖关系,但是如果每个实现都相对较大或者创建起来很昂贵,那么这不是一个好主意。

  1. Change the provides method to take in a collection of all of the dependencies for the different implementations. 更改提供方法以接收不同实现的所有依赖关系的集合。

     @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); } } 

This is slightly better than option 1 in that Dagger doesn't have to instantiate every single implementation, however it still needs to instantiate all of the dependencies even though they might not be used in all cases. 这比选项1略好,因为Dagger不必实例化每个实现,但是它仍然需要实例化所有依赖项,即使它们可能并非在所有情况下都使用。 I'm also back to creating the objects myself even though they could be created by Dagger. 即使它们可以由Dagger创建,我也会自己创建对象。

  1. Create one module per implementation and instantiate the appropriate module. 为每个实现创建一个模块并实例化相应的模块。 So something like: 所以类似于:

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

This would be fine, but now I have issues defining the component that depends on the module. 这没关系,但现在我在定义依赖于模块的组件时遇到了问题。

What's the best way to tackle this problem? 解决这个问题的最佳方法是什么?

One suggestion has been to try option 1 with the parameters wrapped in Lazy. 一个建议是尝试选项1,参数包含在Lazy中。 Then I only end up calling .get() on one. 然后我最终只在一个上调用.get()。 I'll try this out when I can and post the results 我会尽可能地尝试并发布结果

A possible solution would be using @Named("foo") annotation in conjunction with favoring component provision method over manual injection, which would however mean that your state would be independent from the module itself, and you'd be the one to make your choice 一个可能的解决方案是使用@Named("foo")注释结合有利于组件提供方法而不是手动注入,这意味着你的状态将独立于模块本身,你就是那个让你的选择

@Component(modules={FooModule.class})
public interface AppComponent {
    @Named("STATE_1")
    FooInterface fooImpl1();
    @Named("STATE_2")
    FooInterface fooImpl2();
    ...
    @Named("STATE_10")
    FooInterface fooImpl10();
}

@Module
public FooImpl1Module {
    @Provides
    @Named("STATE_1")
    FooInterface provideFooImpl1(Context context) {
        return new FooImpl1(context);
    }

    @Provides
    @Named("STATE_2")
    FooInterface provideFooImpl2(Context context) {
        return new FooImpl2(context);
    }

    ...

    @Provides
    @Named("STATE_10")
    FooInterface provideFooImpl10(Context context) {
        return new FooImpl10(context);
    }
}

Then you can call 然后你可以打电话

FooInterface fooInterface = component.fooImpl1();

Rather than Lazy<T> , do option 1 with Provider<T> . 而不是Lazy<T> ,使用Provider<T>执行选项1。 Lazy<T> is just a Provider<T> that memoizes locally (with the necessary double-checked locking), but because you know you'll only call one Provider exactly once, you can just inject the Provider instead and skip the synchronization overhead. Lazy<T>只是一个在本地进行memoizes的Provider<T> (带有必要的双重检查锁定),但是因为你知道你只需要调用一个Provider一次,所以你可以只注入Provider并跳过同步开销。

@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();
    }
}

Option 2 will work, but you'll effectively skip the dependency wiring that Dagger could easily do for you, and Option 3 won't work as stated because your @Component annotation needs your list of modules to be a compile-time constant for your Dagger code generation to work. 选项2可以工作,但是你会有效地跳过Dagger可以轻松为你做的依赖连接,而选项3将无法按照规定工作,因为你的@Component注释需要你的模块列表是你的编译时常量匕首代码生成工作。

(A variant of Option 3 could work if your binding were to a constant or a zero-dependency class of one form or another, because then you could pass in an arbitrary subclass of your Module into your Component builder. However, Dagger can only analyze the bindings in the superclass module, and you'd have trouble if your @Provides method implementations take different parameters as yours would, so the switch is the best and clearest alternative I can think of.) (如果您的绑定是一个或另一个形式的常量或零依赖类,则选项3的变体可以工作,因为这样您就可以将模块的任意子类传递到组件构建器中。但是,Dagger只能分析超类模块中的绑定,如果您的@Provides方法实现采用与您不同的参数,则会遇到麻烦,因此switch是我能想到的最好和最清晰的选择。)

Have you tried something like this? 你尝试过这样的事吗?

public class hectic extends Iam {

    String tokenizer heccas = new string tokenizer();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM