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的簡單使用就介紹完畢了,如果有對一些基礎概念不是很理解的童鞋,可以查看官方文檔。