android - 通过模块与注入(inject)构造函数进行 Dagger 2 配置

标签 android kotlin dagger-2

我正在尝试将 dagger-android 添加到 Kotlin 项目中,但当需要创建模块以及仅声明 Inject 构造函数就足够时,我感到很困惑。

假设有以下依赖图:

Activity
    -> ViewModel
        -> Repository
            -> Webservice
            -> Dao
                -> Database
                    -> Application

为了为 Activity 提供 ViewModel,我们为 Activity 和 ViewModel 工厂创建各自的模块,然后在 Activity 中手动创建 ViewModel,如下所示:

@Module
abstract class ActivityModule {
    @ContributesAndroidInjector
    abstract fun mainActivity(): MainActivity
}

// Skiping ViewModelKey and ViewModelFactory code for brevity
@Module
abstract class ViewModelModule {
    @Binds
    internal abstract fun bindViewModelFactory(
        factory: ViewModelFactory
    ): ViewModelProvider.Factory

    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel::class)
    internal abstract fun mainViewModel(viewModel: MainViewModel): ViewModel
}

class MainActivity : DaggerAppCompatActivity() {
    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        viewModel = ViewModelProviders.of(this, viewModelFactory)
            .get(HomeViewModel::class.java)
    }
}

要为ViewModel提供Repository,我们只需声明@Inject构造函数,如下所示:

class MainViewModel @Inject constructor(private val repository: Repository): ViewModel() {}

为了为Repository提供WebserviceDao以及为Dao提供Database,我们创建了各自的模块像这样:

@Module
class NetworkModule {
    @Provides
    @Singleton
    fun provideWebservice() = Webservice.create()
}

interface Webservice {
    ...
    companion object Factory {
        fun create(): Webservice {
            ...
            return retrofit
        }
    }
}


@Module
class DataModule {
    @Provides
    @Singleton
    fun provideApplicationDatabase(app: Application) =
        AppDatabase.getDatabase(app)

    @Provides
    @Singleton
    fun provideUserDao(db: AppDatabase) = db.userDao()
}

@Database(...)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao

    companion object {
        fun getDatabase(context: Context): AppDatabase {
            ...
            return instance
        }
    }
}

通过 AppComponent 和 Application 类中的某种魔法,为数据库提供了Application

@Singleton
@Component(modules = [
    AndroidSupportInjectionModule::class,
    NetworkModule::class,
    DataModule::class,
    ViewModelModule::class,
    ActivityModule::class
])
interface AppComponent: AndroidInjector<App> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun create(application: Application): Builder
        fun build(): AppComponent
    }
}

class App : DaggerApplication() {
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> =
        DaggerAppComponent.builder().create(this).build()
}

问题是:

  1. 数据库如何获取应用程序实例?是 AndroidSupportInjectionModule 发挥了魔力吗?
  2. 为什么我们需要为 Web 服务和数据库创建模块,而不是存储库? 是否可以对 Web 服务接口(interface)和数据库类本身进行注释,以跳过为它们创建单独的 dagger 模块?

最佳答案

问题1数据库如何获取Application实例?是 AndroidSupportInjectionModule 发挥了魔力吗?

答案:不,这不是 AndroidSupportInjectionModule 的工作。 AndroidSupportInjectionModule 包含在 Dagger Android 支持中,这有助于

“配置绑定(bind)以确保 dagger.android 和 dagger.android.support 框架类的可用性。” Found Here

所以,基本上,当您创建 Dagger Builder 时,您只需传递应用程序上下文,现在只需从应用程序类传递它。一旦您在主组件中获得它,您的所有模块中就有了应用程序上下文,当我们需要上下文时,我们需要上下文。初始化房间数据库。

问题2为什么我们需要为Web服务和数据库创建模块,而不是存储库?是否可以注释 Web 服务接口(interface)和数据库类本身以跳过为它们创建单独的 dagger 模块?

答案: 首先,始终尝试实现构造函数注入(inject)。模块的总体思想是“如果我们不拥有该类,我们就无法@annotate它的构造函数,因此我们创建模块来提供它们的实现”。另外,如果我们想注入(inject)接口(interface),我们可以通过其实现类的构造函数注入(inject)来实现它。
因此,我们不拥有 WebService 和数据库的初始化,这就是为什么我们创建它们的模块并提供它们,以便我们可以在我们的存储库中获取它们的实例。我们拥有我们的存储库类,因此我们可以通过构造函数注入(inject)来注入(inject)它们。

关于android - 通过模块与注入(inject)构造函数进行 Dagger 2 配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59843328/

相关文章:

android - 使用 Dagger 2 注入(inject)服务

自定义适配器中的 Android Dagger 2 依赖注入(inject)

android - 降低 Tab 高度并在顶部对齐文本?

android - 如何在 Android 中的 Activity/任务更改时收到通知

kotlin - Kotlin:如何处理任何输入类型和给定输出类型的功能

android - 在 Paging 3 库 Android Kotlin 中更新当前页面或更新数据

android - Admob - 广告加载失败 : 3

android - Kotlin 将 val 字段添加到具有多个构造函数的子类

android - Kotlin : Sign In using google Fails

android - 组件(无作用域)可能不引用作用域绑定(bind)