我正在尝试将 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
提供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
}
}
}
通过 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()
}
问题是:
- 数据库如何获取应用程序实例?是 AndroidSupportInjectionModule 发挥了魔力吗?
- 为什么我们需要为 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/