Dagger2使用

ylwh9632 8年前發布 | 10K 次閱讀 Android開發 移動開發

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

 本文由用戶 ylwh9632 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!