Flow的collect函数是Kotlin中的block函数吗?

Is the collect function of Flow a block function in Kotlin?

希望用Room删除Id列表和相关文件的记录

我发现当我运行代码A

时,文件可以删除,记录不能删除

我发现我运行代码B时可以删除记录

好像Log.e("My","Fire")在代码A里没有推出,不知道为什么?

Q1:代码A有什么问题?

Q2:我使用Flow时collect是块函数吗?

Q3:fun getByID(id:Int): Flow<RecordEntity?>是好的设计吗?也许应该是 fun getByID(id:Int): RecordEntity? .

代码A

class RecordRepository @Inject constructor(
    private val mRecordDao:RecordDao
) {   
    override fun getByID(id:Int): Flow<MRecord?> =  mRecordDao.getByID(id).map {it?.let{ModelMapper.entityToModel(it) } }
 

    override suspend fun deleteRecord(idList: List<Int>) = withContext(Dispatchers.Default) {
        idList.forEach{
            getByID(it).collect {
               it?.let {
                   val filename = it.soundFileName
                   deleteFileOrFolder(filename)
               }
            }
        }
        Log.e("My","Fire")
        mRecordDao.deleteRecord(idList)
    }

}

@Dao
interface  RecordDao {
    @Query("SELECT * FROM record_table where id=:id")
    fun getByID(id:Int): Flow<RecordEntity?> 

    @Query("delete from record_table where id in (:idList)")
    suspend fun deleteRecord(idList: List<Int>)
}

代码B

class RecordRepository @Inject constructor(
    private val mRecordDao:RecordDao
) {   
    override fun getByID(id:Int): Flow<MRecord?> =  mRecordDao.getByID(id).map {it?.let{ModelMapper.entityToModel(it) } }


    override suspend fun deleteRecord(idList: List<Int>) = withContext(Dispatchers.Default) { 
        mRecordDao.deleteRecord(idList)
    }

}

//The same

新增内容:

致 Arpit Shukla:谢谢!

我发现许多查询示例 return 使用代码 C 与 Room 流动数据。

我觉得Code D就够了,而且很简单

我很困惑为什么我需要在 Room 中使用 Flow,你知道我最多只想要一次实体,你能告诉我吗?

代码C

@Dao
interface  RecordDao {
    @Query("SELECT * FROM record_table ORDER BY createdDate desc")
    fun listRecord():  Flow<List<RecordEntity>>
}

代码D

@Dao
interface  RecordDao {
    @Query("SELECT * FROM record_table ORDER BY createdDate desc")
    suspend  fun listRecord(): List<RecordEntity>
}

collect 函数永远挂起。它永远不会恢复。所以你放在 collect 之后的任何代码都不会被执行。这是代码A的问题。

如果你想让代码 A 工作,你应该使用 launch 函数在单独的协程中收集每个流。

override suspend fun deleteRecord(idList: List<Int>) = withContext(Dispatchers.Default) {
    idList.forEach {
       launch {
           getByID(it).collect {
               it?.soundFileName?.let { deleteFileOrFolder(it) }
           }
       }
    }
    Log.e("My","Fire")
    mRecordDao.deleteRecord(idList)
}

此外,您无需在代码中切换 Dispatchers,Room 会自动完成。

编辑: 如果您只需要获取一次 RecordEntity 的列表,代码 D 是更好的方法。当我们需要观察查询结果的变化时,需要Flow。例如,在 UI 中显示 RecordEntity 的列表时,如果数据库中的数据发生变化,我们希望更新 UI,为此我们可以 return Flow 来自道.

对于您的具体情况,您可以这样做:

@Dao
interface  RecordDao {
    @Query("SELECT * FROM record_table where id=:id")
    suspend fun getByID(id:Int): RecordEntity?
}

override suspend fun deleteRecord(idList: List<Int>) {
    idList.forEach { id ->
        getByID(id)?.soundFileName?.let { deleteFileOrFolder(it) }
    }
    Log.e("My","Fire")
    mRecordDao.deleteRecord(idList)
}