2017-04-12 190 views
12

使用新的(在2.10中)dagger.android類,我試圖使用依賴於其他模塊的子組件注入事物,因此,有一個具有這些模塊的setter的Builder。有關https://google.github.io/dagger/android.html的文檔描述了這一點,但不清楚如何實際編寫和/或調用這些設置器。Dagger 2.10 Android子組件和構建器

從上面的鏈接引用:

AndroidInjection.inject() gets a DispatchingAndroidInjector from the Application and passes your activity to inject(Activity). The DispatchingAndroidInjector looks up the AndroidInjector.Factory for your activity’s class (which is YourActivitySubcomponent.Builder), creates the AndroidInjector (which is YourActivitySubcomponent), and passes your activity to inject(YourActivity).

在我看來,爲了能夠調用的setter方法生成器,我需要在那裏得到的地方,並確保生成器擁有所有必要的數據?我看到的問題是,在運行時,我得到一個IllegalStateException: MODULE must be set,當我的子組件生成的構建器由AndroidInjector調用。

問題的子組件實際上是一個片段,而不是一個活動,但我不知道這應該重要。有關如何做到這一點的任何想法?

+1

參見[這](https://android.jlelse.eu/android-and-dagger-2-10-androidinjector-5e9c523679a3),最有可能會解決你的問題。 – azizbekian

+1

你可以發佈一些簡化的代碼嗎?你無法設置哪個模塊? –

回答

25

總之,你應該override the call to seedInstance在Builder(這是一個抽象類,而不是一個接口),提供您所需要的其他模塊。

編輯:在此之前,檢查並確保您確實需要通過該模塊。由於Damon added in a separate answer,如果您爲Android類創建了特定的模塊,您可以依靠該類的自動注入來將配置或實例從該圖上拉出。如果僅僅從模塊中消除構造函數參數更容易,也可以提供更好的性能,因爲它們避免了不必要的實例和虛方法調用。


首先,dagger.android在30秒:而不是具有各活動或片段知道它的父,活動(或片段)調用AndroidInjection.inject(this),其檢查HasActivityInjector(或父片段的應用,活動和申請HasFragmentInjector)。這個想法是,你貢獻了一個綁定到一個multibindings創建Map<Class, AndroidInjector.Factory>,其中貢獻綁定幾乎你寫的構建特定對象的子始終子建設者。

正如你可能從AndroidInjection.inject(this)AndroidInjector.Factory.create(T instance)告訴,你沒有得到很多的機會,通過特定活動或特定片段,向您詳細介紹構建的。取而代之的是,這個想法是,你的子組件構建覆蓋seedInstance實施。如在文檔的seedInstance

Provides instance to be used in the binding graph of the built AndroidInjector . By default, this is used as a BindsInstance method, but it may be overridden to provide any modules which need a reference to the activity.

This should be the same instance that will be passed to inject(Object) .

那會是這個樣子:

@Subcomponent(modules = {OneModule.class, TwoModule.class}) 
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> { 

    // inject(YourActivity) is inherited from AndroidInjector<YourActivity> 

    @Builder 
    public abstract class Builder extends AndroidInjector.Builder<YourActivity> { 
    // Here are your required module builders: 
    abstract Builder oneModule(OneModule module); 
    abstract Builder twoModule(TwoModule module); 

    // By overriding seedInstance, you don't let Dagger provide its 
    // normal @BindsInstance implementation, but you can supply the 
    // instance to modules or call your own BindsInstance: 
    @Override public void seedInstance(YourActivity activity) { 
     oneModule(new OneModule(activity)); 
     twoModule(new TwoModule(activity.getTwoModuleParameter())); 
    } 
    } 
} 

這裏的假設是,你需要等待activity實例模塊。如果沒有,那麼你也有調用這些的選項,當您綁定子:

@Provides @IntoMap @ActivityKey(YourActivity.class) 
AndroidInjector.Factory bindInjector(YourActivitySubcomponent.Builder builder) { 
    return builder 
     .oneModule(new OneModule(...)) 
     .twoModule(new TwoModule(...)); 
} 

...但如果你能做到這一點,那麼你可以更輕鬆地通過重寫這些模塊照顧那些綁定,實現可供給模塊的構造函數參數零參數的構造函數,並讓匕首創造者,因爲它確實爲公共零參數構造的任何模塊。

+0

完美,謝謝! –

+2

這完全工作!這在文檔中沒有提及,但是這使得使用匕首2 +的新用戶難以理解文檔。 – ArunL

+0

不知道爲什麼我的實現返回一個錯誤爲「錯誤:(154,5)錯誤:方法沒有覆蓋或實現超類型的方法」 –

2

確實有效,但沒有必要。 seedInstance方法將活動實例提供到圖中,因此您可以讓MyActivityModule沒有狀態,只需在@Provides方法中請求MyActivity。

class MyActivityModule { 
    @Provides 
    static SomethingDerivedFromMyActivity providesMethod(MyActivity myActivity) { 
    return myActivity.somethingDerived(); 
    } 
} 

這樣做節省了模塊實例,並允許生成的工廠要精簡。

https://github.com/google/dagger/issues/615

+0

+1:你(和我的同事Ron)是對的,當然,假設你的設置足夠重新編輯模塊以包含對你的Activity的引用。如果你的模塊來自第三方,或者設計用於更多活動而不僅僅是MyActivity,那麼你可能不得不使用我更復雜的設置(本身也在文檔中建議)。假設提問者需要帶有構造函數的有狀態模塊,我回答了這個問題,因爲他們提到需要Builder,但是如果你不這樣做,那麼當然事情可以更容易地表示。 –

+0

同意但我的問題是,當使用您的解決方案時,編譯器大聲抗議「錯誤:(154,5)錯誤:方法不會覆蓋或實現超類型的方法」。我完全按照步驟,在檢查生成的代碼後,我發現錯誤是在'oneModule()'抽象方法的實現中給出的。不知道爲什麼會發生,我正在使用匕首2.10。無論如何,讓我做一些更多的測試,也許我可以在代碼中找到錯誤的地方。 –

+0

你能告訴我嗎?這聽起來像'oneModule'不是公開的或抽象的,或者這個類不是,或者其他。 –

相關問題