【发布时间】:2020-01-21 14:31:22
【问题描述】:
我正在尝试将 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 constructor:
class MainViewModel @Inject constructor(private val repository: Repository): ViewModel() {}
为了为 Repository 提供 Webservice 和 Dao 以及为 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
}
}
}
而 Application 是通过 AppComponent 和 Application 类中的某种魔法为 Dabatabase 提供的
@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()
}
问题是:
- 数据库如何获取应用程序实例?是 AndroidSupportInjectionModule 发挥了作用吗?
- 为什么我们需要为 Web 服务和数据库创建模块而不是存储库? 是否可以对 Webservice 接口和 Database 类本身进行注释以跳过为它们创建单独的 dagger 模块?
【问题讨论】:
-
第 1 个问题与 Dagger 工作有关。您可以在初始化代码(构造函数?)中抛出一些异常并查看调用堆栈。顺便说一句,你使用 Dagger 2 吗(版本 2 在查找依赖项的方式上有所不同)?