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 中提供模块即可。
我有两个项目模块(我的意思是两个 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 中提供模块即可。