Android—dagger擴展庫

概述

之前我們使用dagger注入時,都需要activity、fragment等宿主在component中註冊,比如:

((SomeApplicationBaseType) getContext().getApplicationContext())
        .getApplicationComponent()
        .activity(this)
        .build()
        .inject(this);

這樣之後纔可以使用該component中的依賴實例(也可以是父組件中能拿到的),隨着開發的深入,這類代碼越來越多,很不利於重構,同時也打破了依賴注入的核心原則:一個類不應該知道如何注入它。

Dagger.Android庫是Dagger庫的補充,dagger.android中的類提供了一種簡化此模式的方法,從而在一定程度上避免了上述問題的發生。

使用流程

1.在ApplicationComponent中注入AndroidInjectionModule,如果項目中用到v4包的Fragment,還需注入AndroidSupportInjectionModule.建議把兩個Module都注入ApplicationComponent中:

@Component(modules = {AndroidInjectionModule.class, AndroidSupportInjectionModule,...})
public interface ApplicationComponent {
    void inject(MyApplication application);
} 

2.創建Android庫的核心類(Activity、Fragment、Service、IntentService、BroadcasReceiver),需要注意的就是:AndroidInjection.inject(T)方法的調用位置

  1. 在Activity、Service及IntentService的onCreate()中,super.onCreate()方法以前。
  2. 在Fragment中onAttach()中,super.onAttach()方法以前。如果是v4包的Fragment,應調用AndroidSupportInjection.inject()方法。
  3. 在BroadcastReceiver的onReceive()中,super.onReceive之前調用。

3.創建子組件 - @Subcomponent,其繼承自AndroidInjector,而T就是step2創建的Android庫的類型

@Subcomponent
public interface CoffeeReceiverSubcomponent extends AndroidInjector<CoffeeReceiver> {
    @Subcomponent.Builder
    public abstract class Builder extends AndroidInjector.Builder<CoffeeReceiver> {

    }
}

4.創建Module,其subcomponents屬性值就是3創建的子組件。在其內必須聲明一個抽象方法,該抽象方法返回AndroidInjector.Factory<?>實例,而其參數爲3創建的XxSubcomponent.Builder實例。

@Module(subcomponents = CoffeeReceiverSubcomponent.class)
public abstract class CoffeeModule {

    @Binds
    @IntoMap
    @BroadcastReceiverKey(CoffeeReceiver.class)
    abstract AndroidInjector.Factory<? extends BroadcastReceiver> bind(CoffeeReceiverSubcomponent.Builder builder);
}  

5.將創建的Module注入到ApplicationComponent中,即把其添加至ApplicationComponent的modules屬性列表

@Component(modules = {AndroidInjectionModule.class, AndroidSupportInjectionModule.class,  CoffeeModule.class, ...})
public interface TodoComponent extends AndroidInjector<TodoApplication> {
    @Component.Builder
    abstract class Builder extends AndroidInjector.Builder<TodoApplication> {
    }
}

6.創建自定義Application,繼承了DaggerApplication,因爲dagger把該添加的DispatchingAndroidInjector添加進去了。但是,並沒有實現v4包的HasSupportFragmentInjector,這裏需要手動添加進去。

public class TodoApplication extends DaggerApplication implements HasSupportFragmentInjector{

    @Inject
    DispatchingAndroidInjector<Fragment> fragmentSupportInjector;

    public void onCreate() {
        super.onCreate();
    }

    @Override
    protected AndroidInjector<TodoApplication> applicationInjector() {
        return DaggerTodoComponent.builder().create(this);
    }

    @Override
    public AndroidInjector<Fragment> supportFragmentInjector() {
        return fragmentSupportInjector;
    }
}

注意:只有當BroadcastReceiver在AndroidManifest.xml中註冊時,才能使用DaggerBroadcastReceiver。 當在動態註冊BroadcastReceiver時,推薦使用構造函數注入。

官方demo使用方式

官方demo中的使用方式簡潔方便,主要是使用了一個註解—@ContributesAndroidInjector

@Target(METHOD)
public @interface ContributesAndroidInjector {
  // 要注入到生成的dagger.Subcomponent中的Module。
  Class<?>[] modules() default {};
}

官方文檔對它是這麼解釋的:爲其註解的方法生成相應的AndroidInjector。該注射器是 dagger.Subcomponent的實現

  • 此註釋必須應用於返回具體的Android框架類型(例如:FooActivity、BarFragment、MyService等)的Module中的抽象方法。
  • 該方法應該沒有參數。

具體可看官方例子mvp-dagger
1.自定義一個application,繼承DaggerApplication:

public class ToDoApplication extends DaggerApplication {
    @Inject
    TasksRepository tasksRepository; // component中暴露出來

    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerAppComponent.builder().application(this).build();
    }
}

2.創建一個管理全局的component:

@Singleton
@Component(modules = {TasksRepositoryModule.class,
        ApplicationModule.class,
        ActivityBindingModule.class,
        AndroidSupportInjectionModule.class})
public interface AppComponent extends AndroidInjector<ToDoApplication> {

    TasksRepository getTasksRepository();

    // Gives us syntactic sugar. we can then do DaggerAppComponent.builder().application(this).build().inject(this);
    // never having to instantiate any modules or say which module we are passing the application to.
    // Application will just be provided into our app graph now.
    @Component.Builder
    interface Builder {

        @BindsInstance
        AppComponent.Builder application(Application application);

        AppComponent build();
    }
}

3.創建一個ActivityBindingModule用於管理所有應用內的activity(子組件)

@Module
public abstract class ActivityBindingModule {
    @ActivityScoped
    @ContributesAndroidInjector(modules = TasksModule.class)
    abstract TasksActivity tasksActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = AddEditTaskModule.class)
    abstract AddEditTaskActivity addEditTaskActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = StatisticsModule.class)
    abstract StatisticsActivity statisticsActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = TaskDetailPresenterModule.class)
    abstract TaskDetailActivity taskDetailActivity();
}

4.每個activity都可以再通過module屬性繼續提供依賴或子組件

@Module
public abstract class TasksModule {
    @FragmentScoped
    @ContributesAndroidInjector
    abstract TasksFragment tasksFragment();

    @ActivityScoped
    @Binds abstract TasksContract.Presenter taskPresenter(TasksPresenter presenter);
}

如上的tasksFragment()中 @ContributesAndroidInjector也可以有module繼續依賴下去

TasksRepositoryModule可以當做一個全局的數據module,ApplicationModule可以提供一些全局實例,如網球請求的client等等,AndroidSupportInjectionModule則是使用v4包時需要注入的。

總結

擴展庫可以使dagger的使用更爲簡單方便,具體的需要查看官方demo學習後多加練習細細體會

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章