Dagger2使用

在簡單使用了一段時間的dagger2之后,來談?wù)剬agger2淺薄的認知。

首先,使用依賴注入可以帶來哪些好處?

1、依賴的注入和配置獨立于組件之外,注入的對象在一個獨立、不耦合的地方初始化,這樣在改變注入對象時,我們只需要修改對象的實現(xiàn)方法,而不用大改代碼庫。

2、依賴可以注入到一個組件中:我們可以注入這些依賴的模擬實現(xiàn),這樣使得測試更加簡單。

3、app中的組件不需要知道有關(guān)實例創(chuàng)建和生命周期的任何事情,這些由我們的依賴注入框架管理的。

我覺得,dagger2這樣的依賴注入框架對MVP架構(gòu)來說,是最好的解耦工具,可以進一步降低modle-view-presenter之間的耦合度。
所以,如果你的項目在使用MVP架構(gòu)開發(fā),強烈建議配合dagger2一起使用。

接下來,在貼代碼之前,我先說說明下我的MVP架構(gòu)和傳統(tǒng)的MVP有些不同,傳統(tǒng)MVP的M層處理業(yè)務(wù)邏輯,P層僅僅是V和M的橋梁;而我的P層同時處理與model相關(guān)的業(yè)務(wù)邏輯,不處理View層次的邏輯,View層次的邏輯交給V自己處理,M層僅僅是bean,這種方式是根據(jù)開發(fā)中的實際情況而作的考慮,這里先不作討論。

先看結(jié)構(gòu)圖:


接下來,分解這張圖:
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();  // 數(shù)據(jù)庫管理類
}

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);
    }
}

這里細心的童鞋可能發(fā)現(xiàn),為何有些方法直接返回入?yún)?,有些需要返回一個new的對象呢?
這里如果對DBManager的寫法換成:

DBManager provideDBManager(DBManager dbManager) {
  return dbManager;
}

這樣編譯不會通過,會報一個循環(huán)依賴的錯誤,這種寫法需要在返回參數(shù)和入?yún)⑹抢^承關(guān)系才可以。感興趣的可以查看dagger2生成的代碼。

對于直接返回的類JobExecutor、RetrofitManager,它們類的構(gòu)造函數(shù)一定要加上@Inject的注解:

@Inject
public JobExecutor() {
    // 初始化
    // ......
}

接下來談?wù)凙ctivityComponent,可以看到有個@ActivityScope注解,這個注解是自定義的,對應(yīng)Activity的生命周期,Dagger2可以通過自定義注解限定注解作用域。

@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,同時規(guī)定Activity所對應(yīng)的域是@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里?
是的,正常來說,結(jié)構(gòu)圖應(yīng)該是下面這張圖的樣子:


我建議使用這種方式,對于不同的Activity,創(chuàng)建各個對應(yīng)的ActivityCompontent,同時把Presenter(Biz)注入到Component的視圖中,這也是dagger2推薦的做法,Dagger 2希望使用@Component注解接口將依賴關(guān)系鏈接起來。

而我的做法沒有把Presenter注入到ActivityComponent中,因為Presenter的作用域和Activity一樣,好處是節(jié)省代碼(- -),大家可以根據(jù)項目情況自行選擇注入方式。

使用:

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容