Dagger:在提供的pojo上注入字段

时间:2014-11-04 09:31:09

标签: java android dependency-injection dagger

目前使用dagger进行测试,我想要做的是实例化并注入不同的Bar实现。如何在提供的字段中注入字段? 例如:

模块:

@Module(
        injects = {
                Main.class
        },
        complete = false,
        library = true
)
public class ExampleTestModule {
    @Provides
    public Foo providesFoo() {
        return new Foo();
    }
    @Provides
    public Bar providesBar(BarImpl impl) {
        // return new BarImpl(); // null
        return impl;
    }
}

主:

public class Main {
    @Inject
    Foo foo;
}

富:

public class Foo {
    @Inject
    Bar bar;
}

栏:

public interface Bar {

}

BarImpl

public class BarImpl implements Bar {
}

测试用例:

public class ApplicationTest extends ApplicationTestCase<Application> {
    public ApplicationTest() {
        super(Application.class);
    }


    public void testFoo() {
        Main main = new Main();
        ObjectGraph.create(new ExampleTestModule()).inject(main);
        assertNotNull(main.foo);
    }

    public void testFooBar() {
        Main main = new Main();
        ObjectGraph.create(new ExampleTestModule()).inject(main);
        assertNotNull(main.foo.bar);
    }
}

Main.Foo不为null,但Main.Foo.Bar为null。

1 个答案:

答案 0 :(得分:9)

您永远不会将bar注入foo

ObjectGraph.create(new ExampleTestModule()).inject(main);

此行仅查看由main注释的@Inject字段,并将其注入。没有递归行为。


解决问题

让我们一步一步走:

  • 您在complete = false中提供了library = trueModule。你应该只在必要时才使用它们。当出现问题时,Dagger会给你警告,这些属性会压制这些警告。例如,删除它们会在编译时引发以下警告:

    Error:(11, 8) error: No injectable members on BarImpl. Do you want to add an injectable constructor? required by providesBar(BarImpl) for ExampleTestModule.
    
  • 让我们向BarImpl添加一个空的可注入构造函数,因为它建议:

    public class BarImpl implements Bar {
        @Inject
        BarImpl(){
        }
    }
    
  • 编译会出现新错误:

    Error:(11, 8) error: Graph validation failed: You have these unused @Provider methods:
    1. ExampleTestModule.providesBar()
    Set library=true in your module to disable this check.
    
  • 显然,providesBar()从未使用过。这意味着,bar中的Foo字段永远不会被注入。你可以做两件事:

    1. 手动注入bar

      ObjectGraph graph = ObjectGraph.create(new ExampleTestModule());
      graph.inject(main);
      graph.inject(main.foo);
      
    2. 使用可注射构造函数(首选项):

      public class Foo {
          Bar bar;
      
          @Inject
          Foo(Bar bar){
              this.bar = bar;
          }
      }
      
  • 使用injectable构造函数,您现在将在providesFoo()中出现编译错误,因为您未在Bar构造函数中提供Foo实例。关于Dagger的好处是,您可以安全地完全删除此方法。由于Foo注释了@Injectable,因此它需要注入一个Foo实例,它使用此构造函数。当它使用这个构造函数时,它注意到它需要一个Bar实例,并注入它。

  • 最后,我们可以从@Inject中的Foo字段中删除Main注释,并创建一个可注入的构造函数。使用ObjectGraph.get(Class<?>),我们可以检索完全实例化的Main实例。


结果

最终结果应如下所示:

模块:

@Module(
        injects = Main.class
)
public class ExampleTestModule {
    @Provides
    public Bar providesBar(BarImpl impl) {
        return impl;
    }
}

主要

public class Main {
    Foo foo;

    @Inject
    Main(Foo foo) {
        this.foo = foo;
    }
}

<强>富

public class Foo {
    Bar bar;

    @Inject
    Foo(Bar bar){
        this.bar = bar;
    }
}

<强>栏:

public interface Bar {
}

<强> BarImpl:

public class BarImpl implements Bar {
    @Inject
    BarImpl(){
    }
}

<强> ApplicationTest:

public class ApplicationTest extends ApplicationTestCase<Application> {

    public ApplicationTest() {
        super(Application.class);
    }


    public void testFoo() {
        Main main = ObjectGraph.create(new ExampleTestModule()).get(Main.class);
        assertNotNull(main.foo);
    }

    public void testFooBar() {
        Main main = ObjectGraph.create(new ExampleTestModule()).get(Main.class);
        assertNotNull(main.foo.bar);
    }
}

结论

从结果中,我们可以得出一些结论:

  • 不要只为您的模块添加library = truecomplete = false。只有在使用多个复杂模块时才需要这样做。
  • 尝试使用注射构造函数。这就是Dagger所建造的,并且效果最佳。额外的好处是,您现在可以拥有private字段,就像它们应该的那样。
  • 使用可注入构造函数时,实际上只需要在注入接口实例时创建providesXXX方法,就像我们对BarBarImpl所做的那样。 因为,嘿,这正是Dependency Injection的用途,对吗?