【问题标题】:Using Dagger 2.11 with android modular project将 Dagger 2.11 与 android 模块化项目一起使用
【发布时间】:2018-03-13 15:36:40
【问题描述】:

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

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

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

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

谢谢。

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

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

我的 AppComponent(匕首根)

@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实现的数据模块(位于数据android模块)

@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)

如果知道我想在 Data android Module 上提供 ISystemManager 实现,在 Network Android Module 上提供 INetworkManager 实现,我该如何解决这个问题?

谢谢。

【问题讨论】:

  • 也许您想向我们展示您拥有的东西?如果您正在寻找一种入门方法,这是我最喜欢的示例:adityaladwa.wordpress.com/2016/05/11/…
  • @DinorahTovar 请检查我的编辑。

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


【解决方案1】:

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

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

@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 来安排他们自己的查询,而无需通过数据库,因为该绑定仅存在于子组件中。

【讨论】:

  • 感谢您的解释。虽然你能告诉我我应该在每个模块中输入什么代码吗?知道这些 dagger 模块和组件/子组件都在它们自己的 Android 模块中。
猜你喜欢
  • 1970-01-01
  • 2018-03-09
  • 2023-03-09
  • 1970-01-01
  • 2019-11-18
  • 1970-01-01
  • 1970-01-01
  • 2018-11-17
  • 1970-01-01
相关资源
最近更新 更多