java - 在 Android 模块化项目中使用 Dagger 2.11

标签 java android dependency-injection dagger-2 modularity

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

一切看起来都很完美,直到我想引入 dagger 来粘合所有模块。问题是我希望每个模块都有自己的 dagger 组件/子组件及其模块,以便提供依赖项并向它们公开要由其他组件或父组件使用的图形。

Google 官方 dagger 文档指出子组件可以直接访问父组件依赖项,反之则不然。然而,在我的例子中,基本组件需要来自数据模块的依赖关系,而后者本身需要来自网络模块的依赖关系。

知道我希望每个 Android 模块最好都有自己的子组件,这个问题有什么解决方案吗?如果不行的话有什么解决办法吗?

谢谢。

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

enter image description here

这就是我设置 Dagger 图的方式

enter image description here

我的AppComponent(Dagger根)

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

数据模块(位于data android模块)应该提供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)

知道我想在数据 android 模块提供 ISystemManager 实现并在网络 Android 模块提供 INetworkManager ,如何解决此问题?

谢谢。

最佳答案

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

但是,如果您确实想要分离图表或创建多个子组件实例,您也可以在作用域 @Provides 方法中创建子组件实例。这样,NetworkComponent 就有一个带有私有(private)绑定(bind)的单独图,但也可以使用您在 AppComponent 中公开的依赖项,并且您还可以确保图中只有一个 NetworkComponent 及其相关绑定(bind)的副本。您还需要在子组件上放置一个 getter(提供方法或工厂方法),以便您可以从外部访问它的一些绑定(bind),这与您需要在 @Component 上使用 getter 或注入(inject)器方法才能发挥作用完全相同。

@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
}
<小时/>

如需进一步引用,请参阅the "Subcomponents for Encapsulation" section有关子组件的 Dagger 2 文档中的内容:

Another reason to use subcomponents is to encapsulate different parts of your application from each other. For example, if two services in your server (or two screens in your application) share some bindings, say those used for authentication and authorization, but each have other bindings that really have nothing to do with each other, it might make sense to create separate subcomponents for each service or screen, and to put the shared bindings into the parent component.

In the following example, the Database is provided within the @Singleton component, but all of its implementation details are encapsulated within the DatabaseComponent. Rest assured that no UI will have access to the DatabaseConnectionPool to schedule their own queries without going through the Database since that binding only exists in the subcomponent.

关于java - 在 Android 模块化项目中使用 Dagger 2.11,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49260158/

相关文章:

Android在特定时间自动执行任务

android - SQLite 没有这样的列

c# - 如何防止在 C# 类中滥用构造函数

java - 接下来我应该学习什么 DI/IoC 框架?

java - 如何用 Java 或 C 监视/采样输出音频?

java - 为什么我会收到 "Exception in thread "main"java.lang.IndexOutOfBoundsException : Index 0 out of bounds for length 0 "

java - 如何使用java访问selenium中具有相同类名的第二个元素

java - TestNG 软断言输出不符合预期

android - 文本在 TextView 中看不清楚?

c# - 依赖注入(inject): setting and sharing properties of scoped service in ASP. NET Core