假设你有一个如下的 Room DB DAO:
@Dao
interface RoomDao
{
@Query("SELECT * FROM $TABLE_NAME WHERE $ITEM_ID = :itemId")
suspend fun getEntry(itemId : String) : Entry?
}
请记住,getEntry
是一个suspend fun
,只能在suspend fun
内部或在coroutineScope
内部或使用runBlocking
方法中调用(这些是协程框架处理/管理所有工作的方式)
现在,有几种调用上述方法的方法
1. 使用片段、活动或viewModel提供的coroutineScope
使用 coroutineScope
意味着您已经启动了一个 coroutine
(可以将其视为轻量级的 Java Thread
),并且不想等待它完成。有两种方式可以实现相同的效果,即 launch
和 async
。从执行方式来看,它们都可以实现相同的功能。它们只是返回不同类型的处理程序,供您修改已启动的 coroutine
。其中一种返回 Job
,您可以通过它查询 coroutine
的状态并取消它,另一种返回 Deffered
对象,您可以通过它访问已启动的 coroutine
返回的值。
当您想要直接访问 Room DB 返回的值时,可以使用此方法。
- 在 Fragment 中:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewLifecycleOwner.lifecycleScope.launch {
val entry = DbInstance.getDao().getEntry("<yourEntryId>")
}
}
在一个活动中
override fun onCreate(savedInstanceState: Bundle?) {
lifecycleScope.launch {
val entry = DbInstance.getDao().getEntry("<yourEntryId>")
}
}
在viewModel中
fun launchEntryCall(itemId: String) {
viewModelScope.launch {
val entry = DbInstance.getDao().getEntry("<yourEntryId>")
}
}
使用
GlobalScope
(不建议)。
fun launchEntryCall(itemId: String) {
GlobalScope.launch {
val entry = DbInstance.getDao().getEntry("<yourEntryId>")
}
}
GlobalScope
不建议使用,因为你必须自己管理作为 GlobalScope
启动的协程的生命周期,而 GlobalScope
与提供的 android 类中的 coroutineScopes
集成不良,它们往往会使代码变得复杂。
在 fragment 中使用 viewLifecycleOwner.lifecycleScope
,在 activity 中使用 lifecycleScope
,这些都是由 android 库提供的(您可能需要 add 这些)
2. 在其他 suspend fun
中调用
在某些情况下,当您想要调用多个类似的函数并对其进行操作以返回有意义的内容时,这将对您有所帮助。假设您创建了一个函数,该函数调用前一个 getEntry
并检查以下项目是否已从服务器删除,并返回该项目和 null(如果该项目已被删除)。您可以使用以下代码模拟相同的操作
suspend fun getItemIfNotDeleted(itemId: String): Entry? {
val entry = DbInstance.getDao().getEntry(itemId)
entry ?: return null
return if (isDeleted(entry.url)) {
null
} else {
entry
}
}
3. 使用 runBlocking
(不建议在生产代码中使用)
runBlocking
阻塞当前线程的执行,直到协程返回或抛出异常。因此,假设您想测试上述函数,您可以调用 runBlocking
并获取结果,然后像下面的代码片段一样进行断言测试。
@Test
fun verifyItemReturnedIsNotNull() {
val entry = runBlocking {
DbInstance.getDao().getEntry("<yourEntryId>")
}
assertNotNull(entry)
}
withContext(Dispatchers.Main)
还是使用GlobalScope.launch
来运行我的查询?”-- 使用适当的CoroutineScope
运行launch()
(或者可能是async()
和await()
)。这可以是GlobalScope
,但通常有更好的选择,比如在ViewModel
上使用viewModelScope
,在Activity
上使用lifecycleScope
,在Fragment
上使用viewLifecycleScope
,或者像 此处 所示使用自定义的CoroutineScope
。 - CommonsWare