gpt4 book ai didi

kotlin - 带有 ViewModel、Repository、Room 和 Coroutines 的 Dagger 2

转载 作者:行者123 更新时间:2023-12-02 12:09:35 30 4
gpt4 key购买 nike

我试图在用 Kotlin 编写的 ViewModel + Respository + Room + Retrofit + Coroutines 项目中使用 Dagger 2。

目前,每个 ViewModel 都像这样自行初始化所需的存储库及其依赖项

class HomeViewModel(
application: Application
) : AndroidViewModel(application) {
private val repository: UserRepository =
UserRepository(
Webservice.create(),
AppDatabase.getDatabase(application, viewModelScope).userDao()
)

我想把这个简化成这个
class HomeViewModel @Inject constructor(
private val repository: UserRepository
): ViewModel()

到目前为止我所取得的成就

创建 Dagger 组件和模块
@Singleton
@Component(modules = [
AppModule::class,
NetworkModule::class,
DataModule::class,
RepositoryModule::class
])
interface AppComponent {
val webservice: Webservice
val userRepository: UserRepository
}

@Module
class AppModule(private val app: Application) {
@Provides
@Singleton
fun provideApplication(): Application = app
}

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

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

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

@Module
class RepositoryModule {
@Provides
@Singleton
fun provideUserRepository(webservice: Webservice, userDao: UserDao) =
UserRepository(webservice, userDao)
}

在应用程序类中初始化了 AppComponent
class App : Application() {
companion object {
lateinit var appComponent: AppComponent
}
override fun onCreate() {
super.onCreate()
appComponent = initDagger(this)
}
private fun initDagger(app: App): AppComponent =
DaggerAppComponent.builder()
.appModule(AppModule(app))
.build()
}

现在我被困住了。

第一个问题是 : 如何使 ViewModel 的注入(inject)构造函数工作?

最初它是这样从 HomeFragment 初始化的
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProviders.of(this).get(HomeViewModel::class.java)

我现在如何调用初始化程序?

第二个问题是有点难。

数据库构造函数需要一个 Coroutine 范围,以便在创建期间在后台线程中预填充它。我现在如何传递一个范围?

这是数据库和回调的定义
@Database(
entities = [User::class],
version = 1, exportSchema = false
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao

companion object {
@Volatile
private var INSTANCE: AppDatabase? = null

fun getDatabase(context: Context, scope: CoroutineScope): AppDatabase {
val tempInstance =
INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"database"
)
.fallbackToDestructiveMigration()
.addCallback(AppDatabaseCallback(scope))
.build()
INSTANCE = instance
return instance
}
}
}

private class AppDatabaseCallback(
private val scope: CoroutineScope
) : RoomDatabase.Callback() {RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
INSTANCE?.let { database ->
scope.launch(Dispatchers.IO) {
//inserts
}
}
}
}
}

最佳答案

The second question is a bit harder.

The database constructor requies a Coroutine scope in order to prepopulate it in a background thread during creation. How do I pass in a scope now?



实际上更简单,不要传入 CoroutineScope , 使用 GlobalScope对于这个操作。

The first question is: How do I make the ViewModel's inject constructor work?



您需要获取 Provider<HomeViewModel>来自 Dagger,然后在 ViewModelProvider.Factory 中调用它创建 HomeViewModel 的实例通过在 Dagger 组件中注册的提供程序。

或者,如果 Activity 有自己的子组件,那么您可以使用 @BindsInstance将 Activity 实例放入图中,然后移动 ViewModelProviders.of(activity).get(HomeViewModel::class.java, object: ViewModelProvider.Factory {
...
return homeViewModelProvider.get() as T
...
})
进入该子组件的模块。然后,从该子组件中,可以获得 HomeViewModel 的实际实例。 , 并且仍然获得适当的作用域 + onCleared()打回来。

关于kotlin - 带有 ViewModel、Repository、Room 和 Coroutines 的 Dagger 2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59822514/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com