这里有一些问题,但我将首先解决主要问题。
fun getUserFromDB() {
val profileDao = AppDatabase.getDatabase(context).getProfileDao()
CoroutineScope(Dispatchers.IO).launch {
val userProfile = profileDao.getUserProfile().await()
}
return userProfile
}
在getUserFromDB 中,launch 从getUserFromDB 异步执行,并且在您返回之前不会完成。
为了保证完成,你有两个选择(如果你想使用协程)。
- 将
getUserFromDB 标记为挂起函数。 (强烈推荐)
suspend fun getUserFromDB() {
val profileDao = AppDatabase.getDatabase(context).getProfileDao()
val userProfile = withContext(Dispatchers.IO) {
profileDao.getUserProfile().await()
}
return userProfile
}
- 使用
runBlocking。
fun getUserFromDB() {
val profileDao = AppDatabase.getDatabase(context).getProfileDao()
val userProfile = runBlocking(Dispatchers.IO) {
profileDao.getUserProfile().await()
}
return userProfile
}
现在主要问题已解决。这里有几件事违反了惯例和准则。
-
getUserProfile 不应该返回 Deferred<Profile>(尤其是如果它已经挂起),因为这是一个不安全的传递原语,它应该只返回 Profile。这样就不会意外引入不需要的并发,也不必写await()。
@Query("SELECT * FROM PROFILE LIMIT 1")
suspend fun getUserProfile(): Profile
fun getUserFromDB() {
val profileDao = AppDatabase.getDatabase(context).getProfileDao()
CoroutineScope(Dispatchers.IO).launch {
val userProfile = profileDao.getUserProfile() /* .await() */
}
return userProfile
}
- 在 Room 中使用协程时,它在专用线程池中执行阻塞调用,因此您不必使用一个(
Dispatchers.IO),在主线程/调度程序中调用是安全的。此答案Why does the querySkuDetails need to run in IO context? 中的更多信息。
fun getUserFromDB() {
val profileDao = AppDatabase.getDatabase(context).getProfileDao()
CoroutineScope(/* Dispatchers.IO */).launch {
val userProfile = profileDao.getUserProfile().await()
}
return userProfile
}
- 最后一点,如果你创建了一个
CoroutineScope 之后没有取消它,你应该只使用GlobalScope 来减少分配的数量。人们说“避免使用GlobalScope。”,这是真的,但你同样应该避免创建CoroutineScopes而不取消它们(我认为它更糟)。
fun getUserFromDB() {
val profileDao = AppDatabase.getDatabase(context).getProfileDao()
GlobalScope.launch(Dispatchers.IO) {
val userProfile = profileDao.getUserProfile().await()
}
return userProfile
}
TL;DR
我已整理好答案,以便您在准备好后可以独立应用每个更改。
如果您只想要所有更改的总和,那么就在这里。
@Query("SELECT * FROM PROFILE LIMIT 1")
suspend fun getUserProfile(): Profile
suspend fun getUserFromDB(): Profile {
val profileDao = AppDatabase.getDatabase(context).getProfileDao()
val userProfile = profileDao.getUserProfile()
return userProfile
}
愉快的编码。 :)