2017-04-07 82 views
13

我開始在我正在開發的應用程序中使用Dagger 2,但我對於Dagger 2的工作原理有一些疑問。Dagger 2注入構造函數

我得到@Provides方法背後的所有邏輯和用於初始化依賴項的@Inject註解,但@Inject對類構造函數的註解類似於我的想法。

例如:

林我的應用程序,我一個模塊定義的,ContextModule,檢索我的申請的上下文中:

ContextModule.java

@Module 
public class ContextModule { 

    private final Context context; 

    public ContextModule(Context context) { 
     this.context = context; 
    } 

    @Provides 
    public Context context() { 
     return this.context; 
    } 
} 

該模塊用於通過我的BaseActivityComponent:

BaseActivityComponent.java

@BaseActivityScope 
@Component(modules = ContextModule.class) 
public interface BaseActivityComponent { 
    void injectBaseActivity(BaseActivity baseActivity); 
} 

到目前爲止這麼好..然後我有一個AuthController類,這取決於上下文,我想注入它在我的BaseActivity。所以在我的AuthControllers.class我有類似:

public class AuthController { 

    private Context context; 

    @Inject 
    public AuthController(Context context) { 
     this.context = context; 
    } 

    public void auth() { 
     // DO STUFF WITH CONTEXT 
    } 
} 

我把它注射在我BaseActivity這樣的:

public class BaseActivity extends AppCompatActivity { 

    @Inject 
    AuthController authController; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     BaseActivityComponent component = DaggerBaseActivityComponent.builder() 
      .contextModule(new ContextModule(this)) 
      .build(); 

     component.injectBaseActivity(this); 

     authController.auth(); 

    } 
} 

現在的問題是,如何做匕首知道我AuthControllers是依賴BaseActivity?只需通過聲明

@Inject 
AuthController authController; 

是一樣的東西,如果我創建了一個ControllerModule,如:

@Module(includes = ContextModule.class) 
public class ControllerModule { 

    @Provides 
    AuthController authController(Context context) { 
     return new AuthController(context); 
    } 

} 

然後在我的BaseActivityComponent我想補充我的AuthController getter和改變我的依賴模塊ControllersModule:

@BaseActivityScope 
@Component(modules = ControllersModule.class) 
public interface BaseActivityComponent { 

    void injectBaseActivity(BaseActivity baseActivity); 

    AuthController getAuthController(); 
} 

當我調用injectBaseActivity(this)它「告訴」匕首所有@Inject註釋是我的類的依賴關係,然後它搜索我的項目ct爲@Inject註釋的構造函數匹配該類型?

我認爲Dagger 2的一個好處就是Module文件可以用作我的依賴關係的「文檔」。但是,如果只是在我控制的所有構造函數中添加@Inject,將來會不會有點困惑,因爲你不知道什麼取決於什麼? (我的意思是,你知道什麼取決於什麼,你只需瀏覽大量的文件,以真正找出)

有沒有什麼最佳做法,當在構造函數中使用@Inject註釋或何時添加@Provides方法在模塊文件? 我在構造函數中使用@Inject我不需要更改我的模塊文件中的構造函數定義,但有什麼缺點嗎?

謝謝。

回答

23

當我打電話injectBaseActivity(這)爲「告訴」匕首所有@Inject註釋是我班的相關性,然後它搜索我的項目@Inject註釋該類型相匹配的構造函數?

沒錯。但是在撥打injectBaseActivity時沒有完成,但這一切都是在編譯期間發生的。這是註釋處理的一種方式(另一個使用運行時反射)。

當您構建項目時,您在build.gradle文件中包含的(作爲依賴項的)匕首註釋處理程序將被調用,並列出所有由@Inject註釋註釋的字段,類等,並構建依賴項圖表與它。然後解析該圖,生成提供圖上項目的所有依賴關係的源代碼。

injectBaseActivity只是執行之前生成的代碼,並將所有依賴關係分配給對象。它是適當的源代碼,您可以閱讀和調試。

這是編譯步驟—的原因簡單地說就是—就是性能和驗證。 (例如,如果你有一些依賴循環,你會得到一個編譯錯誤)


如何匕首知道我AuthControllers是BaseActivity的依賴?

@Inject 
AuthController authController; 

通過註釋字段@Inject匕首知道你想要一個AuthController。到現在爲止還挺好。現在,匕首將尋找一些方法來提供控制器,在組件,組件依賴和組件模塊中尋找它。它也將看看這個類是否可以自己提供,因爲它知道它的構造函數的

如何匕首瞭解對象的構造函數,如果你不包括任何模塊中?

@Inject 
public AuthController(Context context) { /**/ } 

通過與注入註釋構造函數,你還告訴匕首有一個叫AuthController類,你需要一個上下文它被實例化。它基本上與將其添加到模塊中相同。

模塊@Provides如果您沒有源代碼,只需將@Inject註釋添加到構造函數中,或者對象需要進一步初始化,則應該使用該方法。或者在你的情況......

[...]模塊文件可以作爲我的依賴關係樹的「文檔」 [...]

是的,當然你可以去做。但是,隨着你的項目的發展,你將不得不保持不必要的代碼,很多,因爲同樣可能已經在構造一個簡單的註解來實現。

當在構造函數中使用@Inject註釋或何時在模塊文件中添加@Provides方法時,是否有任何最佳做法?

如果要提供不同的版本不同的環境(例如以兩種不同的方式實現一個接口)還有一個@Binds註釋,它告訴匕首你希望提供哪個類作爲實現。

除此之外,我相信你應該在可能的時候總是使用構造函數注入。如果更改了某些內容,則不必觸碰代碼的任何其他部分,而只需編寫更少的代碼,從而減少可能包含錯誤的地方。

而且匕首能夠並且已經通過了解更多的優化了很多,如果你執行不必要的代碼,它會跟你介紹


當然,最後的開銷工作是一切都取決於什麼你認爲是最好的。畢竟它是必須與你的代碼;)

+0

真棒的答案。你知道是否有可能用注入註釋Kotlin默認構造函數(用類定義定義的構造函數)? –

+1

@saiedVanguard這是可能的:'類A @Inject構造函數(...)' –