2014-02-11 106 views
6

使用Dagger時,使用什麼方法可以在通過注入實例化的對象上實現@Inject字段的自由/簡單實例化。用匕首嵌套/遞歸注入

例如,下面的代碼會將一個Bar類型的對象注入到給定的Foo對象中。它將以顯示的兩種方式中的任何一種來執行此操作。但是,每個Bar對象的Sly字段都不匹配該行爲。

public class Foo { 
    @Inject Bar bar; 

    public String getValue() { 
    return "Foo's bar value: " + bar.getValue(); 
    } 
} 

public class Bar { 
    @Inject Sly sly; 

    public String getValue() { 
    return "Bar's sly value: " + sly.getValue(); 
    } 
} 

狡猾

public class Sly { 
    public String getValue() { 
    return "Hey!"; 
    } 
} 

模塊

@Module(
    injects = { 
     Foo.class, 
     Bar.class 
    } 
) 
public class ExampleTestModule { 
    @Provides 
    Bar provideBar() { 
    return new Bar(); 
    } 

    @Provides 
    Sly provideSly() { 
    return new Sly(); 
    } 
} 

測試

public void testWorksWithInject() { 
    Foo foo = new Foo(); 
    ObjectGraph.create(new ExampleTestModule()).inject(foo); 
    assertEquals("...", foo.getValue()); // NullPointerException 
} 

public void testWorksWithGet() { 
    Foo foo = ObjectGraph.create(new ExampleTestModule()).get(Foo.class); 
    assertEquals("...", foo.getValue()); // NullPointerException 
} 

在這兩種情況下,酒吧的狡猾不被注入/ @實例化。當然,Dagger允許構造函數注入,從而解決了這個問題。我想知道是否有替代方法將這些類集合到構造函數的參數列表中。什麼對你有好處?

回答

9

所以這裏的問題是Bar有@Inject狡猾,但是你在@Provides方法中提供Bar。 @Provides方法覆蓋默認的實例化行爲,所以你告訴Dagger實例化「new Bar()」並將它作爲Bar的提供的實現返回。

您可以做的最簡單的事情就是簡單地刪除provideBar()方法,因爲它是不必要的。如果具體類型具有@Inject構造函數或@Inject字段,則Dagger將注入它的依賴關係並創建它,除非它具有不可訪問的構造函數或沒有@Inject的參數化構造函數。但是,您上面的Bar {}以上的案例完全適用於隱式綁定,而不使用@Provides方法。

如果您由於某種原因需要更改默認行爲,您仍然可以在@Provides方法中創建它,但是您必須手動傳入注入的值。 @Provides方法,但是,它們本身可以通過向@Provides方法本身添加參數來注入。所以你可以做到這一點。

@Provides 
Bar provideBar(Sly sly) { 
    Bar bar = new Bar(); 
    bar.sly = sly; 
    return bar; 
} 

一個@Provides方法花費正常供應的情況下,包括newing,分配,任何初始化邏輯等

但是,鑑於你上面的例子,最簡單的辦法是簡單地刪除provideBar全部責任()從模塊中讓Dagger自動初始化Bar。

Dagger 2似乎有利於嵌套注入:請求一個組件,MembersInjector,或給Bar一個@Inject帶註釋的構造函數。

如果酒吧具有@Inject註釋的構造則可以實現完全不變性:

class Bar { 
    private final Sly sly; 

    @Inject 
    public Bar(Sly sly) { 
    this.sly = sly; 
    } 
} 

時僅部分地注入部件的另一種方法是使用一個@Provides方法與MembersInjector或組分(MembersTestComponent ?)作爲方法的參數:

@Provides 
Bar provideBar(MembersInjector<Bar> injector) { 
    Bar bar = new Bar(); 
    injector.inject(bar); 
    return bar; 
} 

提供了MembersTestComponent參數將不幸夫婦的模塊回到你的組件,使解決方案內聚力較小。如果Bar包含組件提供的作用域值(例如Jake Wharton Devoxx 2014討論中的Tweeter中的用戶),提供MembersInjector特別有用。