Android 将 Dagger2 与多个项目模块一起使用

Android using Dagger2 with multiple project modules

我有两个项目模块(我的意思是两个 android 模块有自己的 gradle、清单等。不是 Dagger 模块)。我称它们为 MyAppCore 和 MyApp。 MyAppCore 具有围绕数据库访问和网络访问的逻辑。 MyApp 拥有所有 UI(活动、视图、模型视图等)。

我正在使用 dagger 2 在我的项目中注入不同组件的依赖关系,但是,我无法 link 将两个模块放在一起。

MyApp 和 MyAppCore 有自己的 AppComponent,其中 MyApp 提供 ViewModel 工厂,MyAppCore 提供用于数据库和网络访问的工厂(示例如下)。

我不确定如何 link AppComponent(或应用程序)以便可以在 MyApp 中提供数据库和网络访问。这是我目前所拥有的:

MyAppCore 模块

CoreApp

open class CoreApp : Application() {

    val appComponent: AppComponent by lazy {
        initializeComponent()
    }

    open fun initializeComponent(): AppComponent {
        return DaggerAppComponent.builder()
            .build()
    }
}

应用组件

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder
        fun build(): AppComponent
    }
}

AppModule

@Module
class AppModule {
    @Singleton
    @Provides
    fun provideDb(app: Application) = MyDb.getInstance(app)

    @Singleton
    @Provides
    fun provideCommentDao(db: MyDb) = db.commentDao()
}

CommentRep(访问 CommentDao)

@Singleton
class CommentRep @Inject constructor(private val dao: CommentDao)  {

    fun saveComment(comment: Comment){
        dao.insert(comment)
    }

}

MyAppCore 还有名为 MyDb 的 Room 数据库实现和接口 CommentDao(我不认为我需要在这个问题中添加这段代码)。

MyApp 模块

我的应用程序

open class MyApp : Application(), DaggerComponentProvider {
    override val appComponent: AppComponent by lazy {
        initializeComponent()
    }

    open fun initializeComponent(): AppComponent {
        return DaggerAppComponent.builder()
            .applicationContext(applicationContext)
            .build()
    }
}

DaggerComponentProvider

interface DaggerComponentProvider {
    val appComponent: AppComponent
}

val Activity.injector get() = (application as DaggerComponentProvider).appComponent

应用组件

@Singleton
@Component
interface AppComponent{

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun applicationContext(applicationContext: Context): Builder
        fun build(): AppComponent
    }

    fun commentsViewModelFactory(): ViewModelFactory<CommentsViewModel>
}

ViewModelFactory

class ViewModelFactory<VM : ViewModel> @Inject constructor(
    private val viewModel: Provider<VM>
) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>) = viewModel.get() as T
}

评论视图模型

class CommentsViewModel @Inject constructor(private val repository: CommentRep) : ViewModel() {   
    fun saveComment(comment: Comment){
        repository.saveComment(comment)
    }
}

然后是注入 VM 的活动,但我认为他们没有必要在这个问题中包含他们的代码。

当然,如果我这样编译我的项目,则不会生成来自 MyAppCore 的图表,因此我会收到需要提供 CommentDao 的错误,因为 CommentRep 需要它,即CommentsViewModel 使用。我猜 MyAppCore 应用程序 class 被 MyApp 应用程序 class 覆盖,因此 MyAppCore 的 AppComponent 从未实例化,因此从未在我的图中添加所有核心的注入。我该如何解决这个问题?提前致谢!

只需使用一个组件。首先,将 MyAppCore 模块添加到 MyApp 的 gradle 依赖项中。然后,让 MyApp 模块提供将包含两个项目模块中所有 dagger 模块的组件。

您也可以将 MyAppCore 模块更改为库模块,因为您只需要一个应用程序模块。在您的 build.gradle 文件中,替换:

apply plugin: 'com.android.application'

apply plugin: 'com.android.library'

要将 MyAppCore 模块添加到 MyApp 模块的依赖项中,请添加:

implementation project(":myappcore")

对于您在 MyApp 模块中的组件:

@Singleton
@Component(modules=[MyAppCoreModule::class, MyAppModule::class])
interface AppComponent {
...
}

所以基本上,您只需要在 MyAppCore 中提供模块即可。