为什么我们需要将 DI 接线与 Android 多模块化架构中的实现分开?

Max*_*lov 5 android square dagger-2

Square Inc. 在 Droidcon SF'19 上展示了其内部模块化架构:

https://www.droidcon.com/media-detail?video=380843878

但是,我对一些子弹有点困惑。请你帮助我好吗?

  1. 为什么他们实际上需要:wiring模块?我发现它增加了复杂性:
  • 你会为每个新功能获得额外的 gradle 模块

  • 你必须作出一种全球性注入到您的片段在某处:app,因为碎片在定义:impl模块不能访问它的DaggerComponent,这是在定义:impl-wiring模块。:impl不依赖于:impl-wiring,因为依赖是相反的。

  • 你不能有一个 Android 动态功能模块,因为他们应该知道它是DaggerComponent以便注入它的Fragment。但是没有办法从:app模块进行这种注入,这是动态功能的基本模块。

那么为什么是:wiring模块呢?

可以将:impland:impl-wiring:fakeand合并:fake-wiring在一起以消除上述所有问题。而且,在:demo-apps一个可能只是对依赖要么:impl:fake``, and not on :IMPL接线(or:假wiring```)。

Max*_*lov 0

最终,我想出了以下解决方案:

每个功能都包含以下 gradle 模块:

api

implfake

data:api

data:impl1...data:implNdata:fake

data:wiring

ui

demo

所以,在这里apiimplfake往常一样,但我将数据层分开了。我自己认为有时需要多种不同的数据层实现,例如 - 如果我开发股票图表应用程序,我可以依赖Finnhub Open APIMBOUM API 或提供虚假实现。

因此我有data:apidata:implX。事实上,data:api定义了FeatureRepository接口(一个或多个)并data:implX为它们提供了实际的实现。为了绑定接口和实现,我使用data:wiring,它定义了 Dagger模块组件。此外,我在每个data:implX模块中保留相同的包名称,以便“一次写入”data:wiring模块。为了用另一个实现替换一个实现,我只需更改data:wiring/build.gradle中的一行,其中声明了一种:

implementation project(":data:implA")implementation project(":data:implB")

另外,为了打破我原来问题中提到的混乱,我引入了ui模块,其中包含一些Views特定的功能。片段进入demo(用于测试功能的独立应用程序)或 in ui,它们指的是从功能的Dagger组件viewModel注入的一些绑定。但这里UI和库是分开的。Fragment实例化一个专用的 Dagger组件,该组件使用组件依赖项来引用功能的库绑定,例如交互器存储库等。

因此,总而言之,每个功能的 UI 和业务逻辑实现(“库”)之间的分离使得解决问题成为可能。功能api声明了其作为库的功能的入口点,并且可以通过 Dagger多重绑定:app. 因此它可以进一步用于任何:demo,:ui:dynamic-feature