【问题标题】: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 配置中遗漏了什么以使其正常工作?

【问题讨论】:

  • 这闻起来像一个库错误。

标签: android kotlin android-room kotlin-coroutines flow


【解决方案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() 被调用,等待收集新值。

【讨论】:

    猜你喜欢
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    • 2020-01-04
    • 2019-06-28
    • 2021-10-18
    • 1970-01-01
    • 2021-08-13
    • 2015-07-25
    相关资源
    最近更新 更多