使用Dagger 2.11与android模块化项目

时间:2018-03-13 15:36:41

标签: java android dependency-injection dagger-2 modularity

我从头开始研究一个新的Android项目。在了解了项目范围和所要求的功能之后,我想出了一个模块化架构(基本上将每个功能包装到一个功能或android模块中),看起来如下enter image description here

在我想引入匕首粘合所有模块之前,一切看起来都很完美。问题是我希望每个模块都有自己的dagger组件/子组件和它的模块,以便提供依赖关系并向其展示要由其他组件或父组件使用的图形。

Google官方dagger文档指出子组件可以直接访问父组件依赖项,反之亦然。但是,在我的情况下,基本组件需要来自数据模块的依赖项,而后者本身需要来自网络模块的依赖项。

有没有解决这个问题的方法知道我希望每个android模块最好都有自己的子组件?如果没有,无论如何还有解决方案吗?

谢谢。

编辑: 这是我的项目结构的样子

enter image description here

这就是我设置匕首图的方法

enter image description here

我的AppComponent(Dagger root)

@Singleton
@Component(modules = {
    AppModule.class,
    ActivityBuilder.class,
    AndroidSupportInjectionModule.class
})
public interface AppComponent {

void inject(CatApp application);

@Component.Builder
interface Builder {
    @BindsInstance
    Builder application(Application application);

    AppComponent build();
}
}

我的应用模块

@Module(subcomponents = DataComponent.class)
public class AppModule {

@Provides
@Singleton
Context provideContext(Application application) {
    return application.getApplicationContext();
}
}

我的DataComponent(位于数据android模块)

@Subcomponent(modules = DataModule.class)
public interface DataComponent {

@Subcomponent.Builder
interface Builder {
    DataComponent build();
}
}

应提供SystemManager

实施的数据模块(位于数据安卓模块)
@Module(subcomponents = NetworkComponent.class)
public class DataModule {

@Provides
@Singleton
ISystemManager provideSystemManager(SystemManager systemManager) {
    return systemManager;
}
}

网络组件(位于网络Android模块)

@Subcomponent(modules = NetworkModule.class)
public interface NetworkComponent {

@Subcomponent.Builder
interface Builder {
    NetworkComponent build();
}
}

网络模块(位于网络Android模块),应提供INetWorkManager

的实施
@Module
public class NetworkModule {

@Provides
@Singleton
INetworkManager provideNetworkManager(NetworkManager networkManager) {
    return networkManager;
}
}

我在所有构造函数中使用@Inject注释,所以我的配置都已设置但问题是dagger由于某种原因不编译这些子组件,并且在编译时出现此错误:

Error:(27, 8) error: [dagger.android.AndroidInjector.inject(T)] com.github.andromedcodes.network.INetworkManager cannot be provided without an @Provides-annotated method.
com.github.andromedcodes.network.INetworkManager is injected at
com.github.andromedcodes.data.SystemManager.<init>(networkManager)
com.github.andromedcodes.data.SystemManager is injected at
com.github.andromedcodes.data.di.DataModule.provideSystemManager(systemManager)
com.github.andromedcodes.domain.managers.ISystemManager is injected at
com.github.andromedcodes.domain.interactors.CheckSystemAvailability.<init>(systemManager)
com.github.andromedcodes.domain.interactors.CheckSystemAvailability is injected at
com.github.andromedcodes.chasseautrsor.views.Splash.SplashPresenter.<init>(checkSystemAvailability)
com.github.andromedcodes.chasseautrsor.views.Splash.SplashPresenter is injected at
com.github.andromedcodes.chasseautrsor.di.SplashModule.bindSplashPresenter(presenter)
com.github.andromedcodes.chasseautrsor.views.Contract.Presenter is injected at
com.github.andromedcodes.mvp.BaseActivity.mPresenter
com.github.andromedcodes.chasseautrsor.views.SplashScreenActivity is injected at
dagger.android.AndroidInjector.inject(arg0)

我怎么能解决这个问题,因为我知道我想在Network Android Module和Network Android Module的INetworkManager上提供ISystemManager实现?

谢谢。

1 个答案:

答案 0 :(得分:0)

子组件可以自动访问父组件中绑定的对象。图表,这是有道理的,因为子组件只有一个父组件 - 没有歧义。父组件无法自动访问子组件&#39;图,因为你可以像你一样创建任意数量的子组件实例;它不清楚您尝试访问哪个实例。一般情况下,除非您在对象图上需要不同的变体(您在Guice中使用私有模块或子注入器),或者除非您想隐藏实现细节(例如内部网络对象),否则最好安装您的模块都在同一个组件中并跳过子组件策略。

但是,如果您确实要分离图形或创建多个子组件实例,则还可以在范围@Provides方法中创建子组件实例。这样NetworkComponent就有一个带有私有绑定的单独图形,但也可以使用您在AppComponent中公开的依赖关系,并且还可以确保在图形中只有一个NetworkComponent副本及其相关绑定。您还需要在子组件上放置一个getter(提供方法或工厂方法),这样您就可以从外部访问它的一些绑定,这与您在@Component上需要getter或injector方法的方式完全相同因为它有用。

@Subcomponent(modules = NetworkModule.class)
public interface NetworkComponent {

  /** Allow anyone with a NetworkComponent instance to get the INetworkManager. */
  INetworkManager getINetworkManager();

  @Subcomponent.Builder
  interface Builder {
    NetworkComponent build();
  }
}

/**
 * Creates a singleton NetworkComponent. Install this in AppComponent's module,
 * or in your data module if that encapsulates network calls.
 */
@Singleton @Provides NetworkComponent networkComponent(
    NetworkComponent.Builder builder) {
  return builder.build();
}

/** Make the INetworkManager accessible, but not the NetworkManager impl. */
@Provides static provideNetworkManager(NetworkComponent networkComponent) {
  return networkComponent.getINetworkManager();  // add this to NetworkComponent
}

有关进一步参考,请参阅有关子组件的Dagger 2文档中的the "Subcomponents for Encapsulation" section

  

使用子组件的另一个原因是将应用程序的不同部分相互封装。例如,如果服务器中的两个服务(或应用程序中的两个屏幕)共享一些绑定,比如用于身份验证和授权的绑定,但每个绑定实际上彼此无关,那么创建它们可能是有意义的。为每个服务或屏幕分隔子组件,并将共享绑定放入父组件中。

     

在以下示例中,数据库在@Singleton组件中提供,但其所有实现详细信息都封装在DatabaseComponent中。请放心,没有UI可以访问DatabaseConnectionPool来安排自己的查询而无需通过数据库,因为该绑定仅存在于子组件中。