对于您的情况,@Query("..")fun itemList(): Flow<List<Item>> room 生成流 - 这就像可观察模式,您应该订阅流以接收发出的值。您应该在流上调用 collect 函数,该函数应该从协程范围和 will not blocks main thread 调用(就像在您的示例中使用暂停 @Query 一样)。这就是为什么你不应该考虑线程只是选择正确的范围。 Please see sample for android.
用户调用时只会创建冷流对象:
@Query("..")fun observeItemList(): Flow<List<Item>>
在调用该方法的线程上。要创建流对象room 生成RoomSQLiteQuery 对象:只需从@Query("..") 构建语句的字符串表示并绑定查询参数(如果它们存在)(应用房间的类型转换器)。然后room调用CoroutinesRoom.createFlow()方法创建流对象by flow builder。 flow builder(bock) 的所有代码都将在调用 collect 方法的in context of coroutine 处执行。
我写了一个小例子:
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
fun main() {
println("main thread: ${Thread.currentThread()}") // main thread.
runBlocking {
println("runBlocking thread: ${Thread.currentThread()}") // main thread too.
launch(Dispatchers.Default) {
println("launch thread create flow: ${Thread.currentThread()}")// DefaultDispatcher thread
val myFlow = observeItemList()
launch (newSingleThreadContext("MyOwnThread")){ // declare context of the coroutine
println("launch collect thread: ${Thread.currentThread()}")// MyOwnThread thread
myFlow.collect {
println("flow collect thread: ${Thread.currentThread()}") // in the context of the calling coroutine (MyOwnThread thread)
println("emited value: $it")
}
}
}
println("some code in main.")
}
}
fun observeItemList() : Flow<Int> {
println("call to observeItemList thread: ${Thread.currentThread()}") // DefaultDispatcher thread
return flow{
println("flow builder thread: ${Thread.currentThread()}") // MyOwnThread thread
repeat(3) {
emit(it)
delay(1000)
}
}
}
输出:
main thread: Thread[main,5,main]
runBlocking thread: Thread[main,5,main]
some code in main.
launch thread create flow: Thread[DefaultDispatcher-worker-1,5,main]
call to observeItemList thread: Thread[DefaultDispatcher-worker-1,5,main]
launch collect thread: Thread[MyOwnThread,5,main]
flow builder thread: Thread[MyOwnThread,5,main]
flow collect thread: Thread[MyOwnThread,5,main]
emited value: 0
flow collect thread: Thread[MyOwnThread,5,main]
emited value: 1
flow collect thread: Thread[MyOwnThread,5,main]
emited value: 2
这就是为什么所有用于创建查询语句、参数绑定、创建流对象、按流收集发出的项目的代码都将在您调用的协程上下文(调度程序)的线程上执行:
launch(Right coroutine dispatcher){
// all code works on 'Right coroutine dispatcher'
dao.observeItemList().collect{ }
}
在这种情况下,您只会在创建和启动协程时产生开销。
例如,如果您通过某种方法调用launchIn:
fun test() {
dao.observeItemList().forEach{}.launchIn(scope)
}
然后将在test() 调用线程上创建流,但流的构建器主体和收集将在scope 的调度程序上执行。
在这种情况下,您会在协程创建、启动和创建流对象(不执行流的构建器块)时产生开销。
如果你要在非主线程上运行什么,你应该付出任何代价——在主线程上做一些工作(我的意思是准备一些对象,在其他线程中启动任务)。