📌  相关文章
📜  如何在 Android 的多模块项目中使用 Dagger?

📅  最后修改于: 2022-05-13 01:56:17.132000             🧑  作者: Mango

如何在 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

第 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 的方式。