使用协程流程->收集时房间冻结
Posted
技术标签:
【中文标题】使用协程流程->收集时房间冻结【英文标题】:Room freeze when use coroutine flow->collect 【发布时间】:2020-03-07 03:12:12 【问题描述】:我正在使用 Room (v. 2.2.1) 和协程支持 (v. 1.3.2) 并遵循设置
@Entity(tableName = "simple_table")
data class SimpleEntity(
@PrimaryKey(autoGenerate = true) val id: Long = 0
)
@Dao
interface SimpleDao
@Query("SELECT * FROM simple_table WHERE id = :id")
fun getRecord(id: Long): Flow<SimpleEntity?>
@Insert
suspend fun insert(entity: SimpleEntity)
然后,在我将数据插入到 simple_table 中,自动生成的 id 为 1 之后,我尝试查询
db.simpleDao.getRecord(1).collect
//fetch data
db.close()
永远无法联系到db.close()
。它只是冻结在collect()
方法中。如果我将代码更改为
db.simpleDao.getRecord(1).first
//fetch data
或
db.simpleDao.getRecord(1).take(1).collect
//fetch data
然后它可以正常工作。但是为什么普通的collect()
永远不会结束他们的执行?我在 Room 配置中遗漏了什么以使其正常工作?
【问题讨论】:
这闻起来像一个库错误。 【参考方案1】:改为声明你的论点它。
我检查了 first() 和 take() 函数(运行良好)并与 count() 进行比较(不起作用)。区别在于参数。
尝试改变:
flow.collect
//fetch data
收件人:
flow.collect value ->
//fetch data
我不知道为什么,但这对我有用。
编辑:
first() 和 take() 函数抛出 AbortFlowException()。试试这个:
try
db.simpleDao.getRecord(1).collect
//fetch data
throw AbortFlowException()
catch (e: AbortFlowException)
// Do nothing
db.close()
【讨论】:
Flow
的想法是从后台线程接收一次数据,然后在发生写入时再次接收。不需要使用take(1)
或first()
等,实际上这与使用Flow 时所期望的相反。
“声明你的论点而不是它”。这根本没有意义。如果有错误,它要么在 Room 中,要么在 Flow 中,但不在 Kotlin 中。
@Nicolas 这不是错误。这是正确的流动行为。请参阅“编辑”部分,AbortFlowException()
在这种情况下效果很好,并且在first()
和take()
功能中也是如此。
我同意你的观点,但不同意其他观点。我看到你把它划掉了。
AbortFlowException 是内部异常,无法从代码访问【参考方案2】:
我遇到了同样的问题,已经解决了。
.collect 之后的代码在同一个协程中不起作用! 如果你这样写:
MainScope().launch
db.simpleDao.getRecord(1).collect
//fetch data
/**
* My other code that will be freezed
* */
你应该这样写:
MainScope().launch
launch //new coroutine
db.simpleDao.getRecord(1).collect
//fetch data
// No code here
/**
* My other code that will not be freezed
* */
我认为这完全是因为 slot.awaitPending() 被调用,等待收集新值。
【讨论】:
以上是关于使用协程流程->收集时房间冻结的主要内容,如果未能解决你的问题,请参考以下文章