如何在 Android 的多模块项目中使用 Dagger?
我们了解 Dagger 依赖注入框架以及如何在单个模块项目中使用它。 Dagger 主要用于减少或完全摆脱不必要的样板代码。我们已经看到了 dagger 库在 android 中的逐步使用,在这里查看。但在本文中,我们将要学习的内容远不止于此。我们将学习如何在多模块项目中使用 Dagger,但首先,我们必须了解什么是多模块以及什么是单模块项目,为此让我们考虑以下几点。
- 什么是单模块项目?
- 什么是多模块项目?
- 设计一个多模块应用程序。
- 在多模块应用程序中实现 Dagger。
什么是单模块项目?
在Android中,单模块项目是我们平时最常使用的项目。在此,我们有一个文件夹来管理其中的所有内容,就像所有构建文件和所有其他子文件夹一样。简而言之,单个模块项目通常是单个开发人员或一小群开发人员使用的。在单个模块项目中,我们只有一个 app 文件夹。
什么是多模块项目?
就像在单个模块项目中一样,我们只有一个应用程序模块,我们在其中完成所有工作。但是在多模块中,我们可以创建多个应用模块,因此我们称之为多模块。在大量员工使用多模块项目工作的超大型公司中,这是必要的。最初,您只创建一个模块项目,然后向其中添加不同的模块,它就变成了多模块。在下图中,您可以看到我们有 2 个模块,一个是 app 模块,另一个是 MyApplication 模块。关于如何创建新模块,我们将在接下来的步骤中看到。
设计一个多模块应用程序
设计一个多模块项目根据一些功能或服务分为四个模块。让我们先看看这些模块是什么。
- app:这里app是创建项目时创建的包。
- base:它将是一个包含项目通用代码的模块
- feature-one:它也是一个包含特定功能代码的模块。
- 功能二:它也将是一个包含另一个功能的代码的模块。
所有模块都将在应用程序的 build.gradle 中实现,如下所示。
implementation project(':base')
implementation project(':feature-one')
implementation project(':feature-two')
并且两个功能模块也依赖于基础模块,并将在两个功能的 build.gradle 文件中实现,如下所示,
implementation project(':base')
现在让我们看一下创建多模块项目的分步实现
分步实施
第 1 步:创建一个新项目
要在 Android Studio 中创建新项目,请参阅如何在 Android Studio 中创建/启动新项目。请注意,选择Kotlin作为编程语言。
第 2 步:创建新模块
创建项目后,创建一个新模块,如下所示
只需单击新模块按钮,然后将出现一个屏幕,在该屏幕上只需单击下一步并继续保持该活动中的所有默认设置。就是这样,您的新模块将通过这样做来添加。
在多模块应用程序中实现 Dagger
第 1 步:设置基本模块
首先,我们必须设置基础模块,所以让我们将 dagger 依赖项添加到 build.gradle
implementation “com.google.dagger:dagger:2.27”
kapt “com.google.dagger:dagger-compiler:2.27”
第 2 步:创建基础组件和基础模块
以下是基本组件的代码,只需复制并粘贴即可。
Kotlin
@Singleton
@Component(modules = [BaseModule::class])
interface BaseComponent {
fun inject(app: Application)
fun getNetworkService(): NetworkService
fun getDatabaseService(): DatabaseService
}
Kotlin
@Singleton
@Component(modules = [BaseModule::class])
interface BaseComponent {
fun inject(app: Application)
fun getNetworkService(): NetworkService
fun getDatabaseService(): DatabaseService
}
Kotlin
@FeatureOneScope
@Component(
dependencies = [BaseComponent::class],
modules = [FeatureOneModule::class]
)
interface FeatureOneComponent {
fun inject(activity: FeatureOneActivity)
}
Kotlin
@FeatureTwoScope
@Component(
dependencies = [BaseComponent::class],
modules = [FeatureTwoModule::class]
)
interface FeatureTwoComponent {
fun inject(activity: FeatureTwoActivity)
}
Kotlin
@MainActivityScope
@Component(
dependencies = [BaseComponent::class],
modules = [MainActivityModule::class]
)
interface MainActivityComponent {
fun inject(activity: MainActivity)
}
Kotlin
interface BaseComponentProvider {
fun provideBaseComponent(): BaseComponent
}
Kotlin
class MainActivity : AppCompatActivity() {
@Inject
lateinit var databaseService: DatabaseService
@Inject
lateinit var networkService: NetworkService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMainActivityComponent
.builder()
.baseComponent(InjectUtils.provideBaseComponent(applicationContext))
.build()
.inject(this)
Log.d("DaggerSample_Main", databaseService.toString())
startActivity(Intent(this,FeatureOneActivity::class.java))
}
}
Kotlin
class FeatureOneActivity : AppCompatActivity() {
@Inject
lateinit var databaseService: DatabaseService
@Inject
lateinit var networkService: NetworkService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_feature_one)
DaggerFeatureOneComponent
.builder()
.baseComponent(InjectUtils.provideBaseComponent(applicationContext))
.build()
.inject(this)
Log.d("DaggerSample_FeatureOne", databaseService.toString())
}
}
Kotlin
class FeatureTwoActivity : AppCompatActivity() {
@Inject
lateinit var databaseService: DatabaseService
@Inject
lateinit var networkService: NetworkService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_feature_two)
DaggerFeatureTwoComponent
.builder()
.baseComponent(InjectUtils.provideBaseComponent(applicationContext))
.build()
.inject(this)
Log.d("DaggerSample_FeatureTwo", databaseService.toString())
}
}
下面是基本模块的代码。
科特林
@Singleton
@Component(modules = [BaseModule::class])
interface BaseComponent {
fun inject(app: Application)
fun getNetworkService(): NetworkService
fun getDatabaseService(): DatabaseService
}
步骤 3:为功能 1 和功能 2 创建组件
让我们创建功能一组件,功能一组件将从 BaseComponent 获取它的依赖关系。我们的功能一个组件看起来像,
科特林
@FeatureOneScope
@Component(
dependencies = [BaseComponent::class],
modules = [FeatureOneModule::class]
)
interface FeatureOneComponent {
fun inject(activity: FeatureOneActivity)
}
就像特征一组件一样,我们现在将创建一个特征二组件,如下所示
科特林
@FeatureTwoScope
@Component(
dependencies = [BaseComponent::class],
modules = [FeatureTwoModule::class]
)
interface FeatureTwoComponent {
fun inject(activity: FeatureTwoActivity)
}
第 4 步:主要活动的组件
我们还需要为主要活动创建一个组件,如下所示
科特林
@MainActivityScope
@Component(
dependencies = [BaseComponent::class],
modules = [MainActivityModule::class]
)
interface MainActivityComponent {
fun inject(activity: MainActivity)
}
第 5 步:创建 BaseComponentProvider 接口
我们真正想要实现的是在整个应用程序中共享 BaseComponent 的确切实例。为此,我们必须在我们的基本模块中创建一个基本组件提供者接口,如下所示。
科特林
interface BaseComponentProvider {
fun provideBaseComponent(): BaseComponent
}
第 6 步:使用 MainActivity
现在我们将在 MainActivity 中实际编写一些工作代码,因为我们已经完成了模块和组件的设置。 MainActivity 代码如下所示,确保创建了 baseComponent 接口,否则我们将无法在应用程序之间共享同一个实例。
科特林
class MainActivity : AppCompatActivity() {
@Inject
lateinit var databaseService: DatabaseService
@Inject
lateinit var networkService: NetworkService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMainActivityComponent
.builder()
.baseComponent(InjectUtils.provideBaseComponent(applicationContext))
.build()
.inject(this)
Log.d("DaggerSample_Main", databaseService.toString())
startActivity(Intent(this,FeatureOneActivity::class.java))
}
}
第 7 步:使用功能一和功能二活动
由于已经创建了功能一和功能二组件,我们现在将创建它们各自的活动,其活动中的代码如下。
FeatureOne 活动:
科特林
class FeatureOneActivity : AppCompatActivity() {
@Inject
lateinit var databaseService: DatabaseService
@Inject
lateinit var networkService: NetworkService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_feature_one)
DaggerFeatureOneComponent
.builder()
.baseComponent(InjectUtils.provideBaseComponent(applicationContext))
.build()
.inject(this)
Log.d("DaggerSample_FeatureOne", databaseService.toString())
}
}
FeatureTwo 活动:
科特林
class FeatureTwoActivity : AppCompatActivity() {
@Inject
lateinit var databaseService: DatabaseService
@Inject
lateinit var networkService: NetworkService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_feature_two)
DaggerFeatureTwoComponent
.builder()
.baseComponent(InjectUtils.provideBaseComponent(applicationContext))
.build()
.inject(this)
Log.d("DaggerSample_FeatureTwo", databaseService.toString())
}
}
输出:
MainActivity Output: com.example.gfgdemo.base.data.DatabaseService@63d3f1
FeatureOne Output: com.example.gfgdemo.base.data.DatabaseService@63d3f1
如您所见,MainActivity 和 FeatureOneActivity 的输出是相同的,这意味着在两个活动中使用了相同的实例,这是可能的,因为我们创建了一个 BaseComponentProvider 接口并且不用担心 DataBaseService 对象,这些是简单的对象仅用作示例的类。这就是我们在多模块项目中使用 Dagger 的方式。