使用dagger2進行依賴注入
0. 前言
Dagger2是首個使用生成代碼實現完整依賴注入的框架,極大減少了使用者的編碼負擔,
本文主要介紹如何使用dagger2進行依賴注入。如果你不還不了解依賴注入,請看這一篇。
1. 簡單的依賴注入
首先我們構建一個簡單Android應用。我們創建一個UserModel,然后將它顯示到TextView中。這里的問題是,在創建UserModel的時候,我們使用了前文所說的hard init。一旦我們的UserModel的創建方式發生了改變(比如需要傳入Context對象到構造函數),我們就需要修改所有創建UserModel 的代碼。而我們希望的是,對于UserModel的修改不影響其他模塊的代碼(比如這里的MainActivity)。public class MainActivity extends ActionBarActivity {@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); UserModel user = new UserModel(); ((TextView) findViewById(R.id.user_desc_line)).setText(user.id + "\n" + user.name + "\n" + user.gender); } ...
}</pre>
1.1 構建依賴
我們首先想到的是,將創建UserModel的代碼獨立出來,這樣可以保證MainActivity的代碼不被修改。dagger2中,這個負責提供依賴的組件被稱為Module。我們構建的ActivityModule代碼如下所示。@Module public class ActivityModule {@Provides UserModel provideUserModel() { return new UserModel(); }
}</pre>
可以看到,我們使用@Module標識類型為module,并用@Provides標識提供依賴的方法。1.2 構建Injector
有了提供依賴的組件,我們還需要將依賴注入到需要的對象中。連接提供依賴和消費依賴對象的組件被稱為Injector。dagger2中,我們將其稱為component。ActivityComponent代碼如下:@Component(modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity activity); }
可以看到,Component是一個使用@Component標識的Java interface。interface的inject方法需要一個消耗依賴的類型對象作為參數。
注意:這里必須是真正消耗依賴的類型MainActivity,而不可以寫成其父類,比如Activity。因為dagger2在編譯時生成依賴注入的代碼,會到inject方法的參數類型中尋找可以注入的對象,但是實際上這些對象存在于MainActivity,而不是Activity中。如果函數聲明參數為Activity,dagger2會認為沒有需要注入的對象。當真正在MainActivity中創建Component實例進行注入時,會直接執行按照Activity作為參數生成的inject方法,導致所有注入都失敗。(是的,我是掉進這個坑了。)1.3 完成依賴注入
最后,我們需要在MainActivity中構建Injector對象,完成注入。這部分代碼如下所示。public class MainActivity extends ActionBarActivity { private ActivityComponent mActivityComponent;@Inject UserModel userModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mActivityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule()).build(); mActivityComponent.inject(this); ((TextView) findViewById(R.id.user_desc_line)).setText(userModel.id + "\n" + userModel.name + "\n" + userModel.gender); } ...
}</pre>
首先,我們使用@Inject標志被注入的對象userModel(注意userModel不能為private),之后通過dagger2生成的實現了我們提供的ActivityComponent接口類DaggerActivityComponent創建component,調用其inject方法完成注入。至此,我們使用dagger實現了最簡單的依賴注入。
2. 多層依賴
除了上面這種最簡單的形式,dagger2還可以使用component作為component的依賴,實現多層級的依賴注入。
2.1 構建依賴
我們新創建一個名為ShoppingCartModel的Domain Model。并按照1.1的方法構建其Module如下。@Module public class ContainerModule { @Provides ShoppingCartModel provideCartModel() { return new ShoppingCartModel(); } }
2.2 構建Injector
與1.2不同的是,我們的Injector提供的依賴不僅來自ContainerModule,我們還需要使用之前的ActivityComponent提供的UserModel依賴。@Component(dependencies = ActivityComponent.class, modules = ContainerModule.class) public interface ContainerComponent { void inject(MainActivity mainActivity); }
所以如代碼所示,我們在component后增加ActivityComponent了dependencies參數,使得一個Component成為了另一個Component的依賴。
2.3 低級Component提供依賴
目前的 ActivityComponent代碼如下所示。可以看到其只提供了inject方法,而沒有提供需要的UserModel依賴。我們需要的是將 ActivityModule提供的UserModel傳遞給依賴ActivityComponent的ContainerComponent。@Component(modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity activity); }
修改后代碼如下:@Component(modules = ActivityModule.class) public interface ActivityComponent { // void inject(MainActivity activity); UserModel userModel(); }
可以看到,我們為接口增加了提供UserModel依賴的方法,同時,如果不需要使它直接進行注入,可以去掉其inject方法,此時該Component只作為一種依賴的組織模塊。最后,MainActivity中進行依賴注入的代碼如下。public class MainActivity extends ActionBarActivity { private ActivityComponent mActivityComponent;@Inject UserModel userModel; @Inject ShoppingCartModel cartModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mActivityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule()).build(); ContainerComponent containerComponent = DaggerContainerComponent.builder().activityComponent(mActivityComponent).containerModule(new ContainerModule()).build(); containerComponent.inject(this); ((TextView) findViewById(R.id.user_desc_line)).setText(userModel.id + "\n" + userModel.name + "\n" + userModel.gender + "\n" + cartModel.total); } ...
}</pre>
3. 最后
本文試圖用最簡單的例子介紹Android中如何使用dagger2進行依賴注入,因此有很多dagger2的特性并未涉及,比如@Scope注釋,以及dagger2自動生成代碼的分析調試。關于dagger2更深入的特性的分析,還需要在大量使用后再做出總結。
參考
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!