Dagger2使用
來自: http://www.jianshu.com/p/c2feb21064bb
在簡單使用了一段時間的dagger2之后,來談談對dagger2淺薄的認知。
首先,使用依賴注入可以帶來哪些好處?
1、依賴的注入和配置獨立于組件之外,注入的對象在一個獨立、不耦合的地方初始化,這樣在改變注入對象時,我們只需要修改對象的實現方法,而不用大改代碼庫。
2、依賴可以注入到一個組件中:我們可以注入這些依賴的模擬實現,這樣使得測試更加簡單。
3、app中的組件不需要知道有關實例創建和生命周期的任何事情,這些由我們的依賴注入框架管理的。
我覺得,dagger2這樣的依賴注入框架對MVP架構來說,是最好的解耦工具,可以進一步降低modle-view-presenter之間的耦合度。
所以,如果你的項目在使用MVP架構開發,強烈建議配合dagger2一起使用。
接下來,在貼代碼之前,我先說說明下我的MVP架構和傳統的MVP有些不同,傳統MVP的M層處理業務邏輯,P層僅僅是V和M的橋梁;而我的P層同時處理與model相關的業務邏輯,不處理View層次的邏輯,View層次的邏輯交給V自己處理,M層僅僅是bean,這種方式是根據開發中的實際情況而作的考慮,這里先不作討論。
先看結構圖:

接下來,分解這張圖:
AppComponent: 生命周期跟Application一樣的組件。可注入到自定義的Application類中,@Singletion代表各個注入對象為單例。
@Singleton @Component(modules = AppModule.class) public interface AppComponent { Context context(); // 提供Applicaiton的Context ThreadExecutor threadExecutor(); // 線程池 ApiService apiService(); // 所有Api請求的管理類 SpfManager spfManager(); // SharedPreference管理類 DBManager dbManager(); // 數據庫管理類 }
AppModule: 這里提供了AppComponent里的需要注入的對象。
@Module public class AppModule { private final MyApplication application; public AppModule(MyApplication application) { this.application = application; } @Provides @Singleton Context provideApplicationContext() { return application; } @Provides @Singleton ThreadExecutor provideThreadExecutor(JobExecutor jobExecutor) { return jobExecutor; } @Provides @Singleton ApiService providesApiService(RetrofitManager retrofitManager) { return retrofitManager.getService(); } @Provides @Singleton SpfManager provideSpfManager() { return new SpfManager(application); } @Provides @Singleton DBManager provideDBManager() { return new DBManager(application); } }
這里細心的童鞋可能發現,為何有些方法直接返回入參,有些需要返回一個new的對象呢?
這里如果對DBManager的寫法換成:
DBManager provideDBManager(DBManager dbManager) { return dbManager; }
這樣編譯不會通過,會報一個循環依賴的錯誤,這種寫法需要在返回參數和入參不是同一個類的情況下才可以。感興趣的可以查看dagger2生成的代碼。
對于直接返回的類JobExecutor、RetrofitManager,它們類的構造函數一定要加上@Inject的注解:
@Inject public JobExecutor() { // 初始化 // ...... }
接下來談談ActivityComponent,可以看到有個@ActivityScope注解,這個注解是自定義的,對應Activity的生命周期,Dagger2可以通過自定義注解限定注解作用域,一般在Module里規定scope的生命周期,比如下面的ActivityScope在ActivityModule里綁定。
@Scope @Retention(RUNTIME) public @interface ActivityScope {}
ActivityComponent:生命周期跟Activity一樣的組件,這里提供了inject方法將Activity注入到ActivityComponent中,通過該方法,將Activity中需要注入的對象注入到該Activity中。
@ActivityScope @Component(dependencies = AppComponent.class, modules = ActivityModule.class) public interface ActivityComponent { Activity activity(); void inject(LoginActivity loginActivity); void inject(MainActivity mainActivity); // .... }
ActivityModule:注入Activity,同時規定Activity所對應的域是@ActivityScope
@Module public class ActivityModule { private final Activity activity; public ActivityModule(Activity activity) { this.activity = activity; } @Provides @ActivityScope Activity activity() { return this.activity; } }
至此,注入工作初步完畢了,看到這里,可能有童鞋有疑問,Presenter(或者Biz)的注入在哪里,為何沒在ActivityComponent里?
是的,正常來說,結構圖應該是下面這張圖的樣子:

我建議使用這種方式,對于不同的Activity,創建各個對應的ActivityCompontent,同時把Presenter(Biz)注入到Component的視圖中,這也是dagger2推薦的做法,Dagger 2希望使用@Component注解接口將依賴關系鏈接起來。
而我的做法沒有把Presenter注入到ActivityComponent中,因為Presenter的作用域和Activity一樣,好處是節省代碼(- -),大家可以自行選擇注入方式。
使用:
public class LoginActivity extends BaseActivity implements LoginView, ValidCodeView { @Inject LoginPresenter loginPresenter; @Inject ValidCodePresenter validCodePresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initInject(); // 此處省略N行代碼 } private void initInject() { // 構建Component并注入 getActivityComponent().inject(this); loginPresenter.attachView(this); validCodePresenter.attachView(this); } // 建議寫在基類Activity里 protect ActivityComponent getActivityComponent(){ return DaggerActivityComponent.builder() .appComponent(getAppComponent()) .activityModule(getActivityModule()) .build(); } // 建議寫在基類Activity里 protect ActivityModule getActivityModule(){ return new ActivityModule(this); } // 建議寫在MyApplication類里 public AppComponent getAppComponent(){ return DaggerAppComponent.builder() .appModule(new AppModule((MyApplication)getApplicationContext())) .build(); } }
其中LoginPresenter:
@ActivityScope public class LoginPresenter extends DefaultMvpPresenter<LoginView, RESTResult<UserVO>> { // 此處省略 @Inject public LoginPresenter(ApiService apiService, ThreadExecutor jobExecutor, SpfManager spfManager) { this.apiService = apiService; this.jobExecutor = jobExecutor; this.spfManager = spfManager; } public void login(String mobile, String code) { // todo } }
這樣,dagger2的簡單使用就介紹完畢了,如果有對一些基礎概念不是很理解的童鞋,可以查看官方文檔。