Android 从UI线程请求dao流是安全的

Android 从UI线程请求dao流是安全的,android,android-room,flow,suspend,Android,Android Room,Flow,Suspend,如果我们使用@Query(“..”)fun itemList():List声明一个db操作,我们必须确保代码在后台线程上运行 如果我们将其声明为挂起函数@Query(“..”)suspend fun itemList():List,则room生成的代码将创建一个协同路由,并通过协同路由room.execute-在主线程上安全地调用它 但是使用流返回类型声明的操作呢@Query(“…”)fun itemList():Flow在主线程上调用它们安全吗 我的观点是,看看room生成的源代码,从UI线程

如果我们使用
@Query(“..”)fun itemList():List
声明一个db操作,我们必须确保代码在后台线程上运行

如果我们将其声明为挂起函数
@Query(“..”)suspend fun itemList():List
,则room生成的代码将创建一个协同路由,并通过
协同路由room.execute
-在主线程上安全地调用它

但是使用流返回类型声明的操作呢
@Query(“…”)fun itemList():Flow
在主线程上调用它们安全吗

我的观点是,看看room生成的源代码,从UI线程调用该函数并不是很糟糕。调用线程上运行一些同步的代码-但是db操作是在后台线程上完成的。

对于您的案例
@Query(“…”)fun itemList():Flow
room生成Flow-这就像可观察的模式,您应该订阅流以接收发出的值。您应该在流上调用collect函数,该函数应该从coroutines作用域和调用(就像在您的suspend@Query示例中一样)。这就是为什么您不应该只考虑线程选择正确的范围

当用户调用时,将仅创建冷流对象:

@Query("..")fun observeItemList(): Flow<List<Item>>
输出:

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
这就是为什么所有用于创建查询语句、参数绑定、创建流对象、收集流发出的项的代码都将在您调用的协同路由上下文(dispatcher)线程上执行的原因:

launch(Right coroutine dispatcher){
// all code works on 'Right coroutine dispatcher'
    dao.observeItemList().collect{ }
}
在这种情况下,您只需要在创建和启动协同程序时增加开销

例如,如果您从某个方法调用
launchIn

fun test() {
     dao.observeItemList().forEach{}.launchIn(scope)
}
然后流将在调用线程的
test()
上创建,但流的生成器主体和收集将在
范围的调度程序上执行。
在这种情况下,您会在创建、启动和创建流的对象(而不执行流的构建器块)的协同过程中产生开销


如果你想在一个非主线程上运行任何东西,你应该付出任何代价——在主线程上做一些工作(我的意思是准备一些对象,在其他线程中启动任务)。

你找到解决方案了吗?之前你说过请求流不会阻塞主线程。但是,在请求流时运行的一些同步代码可能会阻塞主线程(仅在请求流时,而不是在流运行时),我们发现影响几乎不存在,我添加了一些额外的解释,我希望我的回答能帮助你,有趣的是,当应用程序创建流对象时,哪些代码可以阻止主线程?
房间
请勿为此触摸任何同步部分。(主线程上运行的任何代码都会阻塞主线程)
fun test() {
     dao.observeItemList().forEach{}.launchIn(scope)
}