您如何组织Dagger 2模块和组件?

时间:2015-08-05 13:32:28

标签: java android dagger-2

你有一个特定的包,你把所有Dagger相关的类放在哪里?

或者你把它们放在他们注入的相关类旁边,例如如果您有MainActivityModuleMainActivityComponent,则将它们与MainActivity放在同一个包中。

另外,我见过很多人将组件定义为内部类,例如在ApplicationComponent类中定义的Application。你认为这是一个好习惯吗?

2 个答案:

答案 0 :(得分:26)

编辑:让我先从这里接近事实这一事实开始,但这是一个反模式,如Martin Fowler撰写的Data Domain Presentation Layering文章{{ 3}},指定您不应该拥有MapperModulePresenterModule,您应该有GalleryModule和{{1}其中包含所有地图制作者,演示者等。

要实现它的智能路线是使用组件依赖关系来为您拥有的每个功能提供原始单例组件。我所描述的是"全栈"分层分离 功能

下面写的是"反模式",您可以将应用程序的顶层模块切换为"层"。这样做有很多缺点。不要这样做。但是你可以阅读并了解不该做的事情。

原文:

通常情况下,只要整个应用程序存在,您就可以使用SomeFeatureModule这样的Component来包含您在整个应用中使用的所有单例依赖项。您可以在Application类中实例化它,并从其他地方访问它。

我目前的项目结构是:

ApplicationComponent

例如,我的是这样的:

+ injection
|- components
   |-- ApplicationComponent.java
|- modules
   |- data
      |-- DbMapperModule.java
      |-- ...
   |- domain
      |-- InteractorModule.java
      |-- ...
   |- presentation
      |-- ...
   |- utils
      |-- ...
|- scope
|- subcomponents
   |- data
      |-- ...
   |- domain
      |-- DbMapperComponent.java
      |-- ...
   |- presentation
      |-- ...
   |- utils
      |-- ...
   |-- AppContextComponent.java
   |-- AppDataComponent.java
   |-- AppDomainComponent.java
   |-- AppPresentationComponent.java
   |-- AppUtilsComponent.java

你需要一个public enum Injector { INSTANCE; private ApplicationComponent applicationComponent; private Injector() { } public ApplicationComponent getApplicationComponent() { return applicationComponent; } ApplicationComponent initializeApplicationComponent(CustomApplication customApplication) { AppContextModule appContextModule = new AppContextModule(customApplication); RealmModule realmModule = new RealmModule(customApplication.getRealmHolder()); applicationComponent = DaggerApplicationComponent.builder() .appContextModule(appContextModule) .realmModule(realmModule) .build(); return applicationComponent; } } ,它可以注入任何你想要现场注入的类的受包保护的字段。

ApplicationComponent

对我来说,@Singleton @Component(modules = { AppContextModule.class, DbMapperModule.class, DbTaskModule.class, RealmModule.class, RepositoryModule.class, InteractorModule.class, ManagerModule.class, ServiceModule.class, PresenterModule.class, JobManagerModule.class, XmlPersisterModule.class }) public interface ApplicationComponent extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent { void inject(CustomApplication customApplication); void inject(DashboardActivity dashboardActivity); ... } 将是AppContextComponent,但实际上并不是它的含义。这些只是创建子范围的一种方法,而不是将组件切割成较小部分的方法。所以我继承的接口实际上只是一个带有提供方法的普通@Subcomponent。其他人也一样。

interface

组件依赖关系(允许您像子组件一样进行子视图)不允许多个范围的组件,这也意味着您的模块将是未绑定的。这是因为您无法从多个范围继承,就像您无法从Java中的多个类继承一样。

无范围提供程序使得模块不会保留单个实例,而是在每次注入调用时保留一个新实例。要获得范围内的依赖关系,您还需要在模块提供程序方法上提供范围。

public interface AppContextComponent {
    CustomApplication customApplication();

    Context applicationContext();

    AppConfig appConfig();

    PackageManager packageManager();

    AlarmManager alarmManager();
}

在应用程序中,如果您在任何地方使用Singleton组件,除非您创建子范围,否则您将不再需要更多组件。如果需要,您甚至可以考虑将模块作为视图和演示者的完整数据提供者。

@Module
public class InteractorModule {
    @Provides
    @Singleton
    public LeftNavigationDrawerInteractor leftNavigationDrawerInteractor() {
        return new LeftNavigationDrawerInteractorImpl();
    }

    ...
}

Subscoping允许您拥有演示者的多个实例,然后可以存储状态。这在例如迫击炮/流量(其中HERE (CLICK THE LINK!))中是有意义的 - 将数据作为"蓝图"提供。

@Component(dependencies = {ApplicationComponent.class}, modules = {DetailActivityModule.class}) 
@ActivityScope
public interface DetailActivityComponent extends ApplicationComponent {
    DataObject data();

    void inject(DetailActivity detailActivity);
}

@Module
public class DetailActivityModule {
    private String parameter;

    public DetailActivityModule(String parameter) {
        this.parameter = parameter;
    }

    @Provides
    public DataObject data(RealmHolder realmHolder) {
        Realm realm = realmHolder.getRealm();
        return realm.where(DataObject.class).equalTo("parameter", parameter).findFirst();
    }
}

答案 1 :(得分:15)

  

你有一个特定的包装,你把所有Dagger相关   类?

     

或者你把它们放在他们注入的相关类旁边,例如如果你   有一个MainActivityModule和MainActivityComponent,你把它们放进去   与MainActivity相同的包。

我没有太多经验,但我可以告诉你我的方法。 也许一些具有更多经验的人可以改进该解决方案或提供他们的观点。

我通常会组织Dagger 2这样的课程:

- di
|
+-- ApplicationComponent class
|    
+-- modules
   |
   +-- AndroidModule class
   |
   +-- WebServiceModule class
   |
   +-- ...
   |
  • di包中包含与Dagger 2和依赖注入相关的类。
  • 在大多数情况下,Android应用程序通常只有一个组件 - 这里它的名称为ApplicationComponent - 我还没有创建一个包含许多Dagger 2组件的Android应用程序而且我已经看过解决方案只有一个组件。
  • modules包中包含Dagger 2模块

我没有为每个活动创建模块。模块组特定功能。例如。与SharedPreferences,EventBus(如果您使用类似的东西),网络连接等接口的系统密切相关的元素可能位于AndroidModule。如果您的项目具有WebService的重要界面,或者其中有很多界面,您可以在WebServiceModule中对它们进行分组。例如,如果您的应用程序负责分析网络,并且具有许多与网络相关的类似任务的接口,则可以在NetworkModule中对这些接口进行分组。当您的应用程序很简单时,您可能只有一个模块。如果它很复杂,你可以有很多模块。在我看来,你不应该在一个模块中有很多接口。遇到这种情况时,您可以考虑将它们拆分为单独的模块。您还可以在一个单独的模块中保留一些特定于您的项目的业务逻辑。

  

另外,我见过很多人将组件定义为内部组件   课程,例如一个在里面定义的ApplicationComponent   应用类。你认为这是一个好习惯吗?

我不确定这是好事还是坏事。我认为没有必要这样做。您可以在扩展get()类的类中创建公共静态Application方法,该类将返回Application的实例作为单例。这是一个更简单的解决方案,我们应该只有一个Application类的实例。如果我们想在单元测试中模拟Context,我们可以接受Context作为参数,并在应用程序代码中,根据情况传递Application Context或Activity Context。

请注意,这只是我的方法,一些经验丰富的开发人员可能会以不同的方式组织他们的项目。