I hope to delete records by Id list and relative files with Room.
I find the files can be deleted and the records can't be deleted when I run Code A
I find the records can be deleted when I run Code B.
It seems that Log.e("My","Fire")
is not launched in Code A. I don't know why?
Q1: What's wrong with Code A ?
Q2: Is the collect
a block function when I use Flow?
Q3: Is fun getByID(id:Int): Flow<RecordEntity?>
good design? maybe it should be fun getByID(id:Int): RecordEntity?
.
Code 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>)
}
Code 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
Added Content:
To Arpit Shukla: Thanks!
I find many query samples to return Flow data with Room using Code C.
I think Code D is enought and it's simple
I'm confused why I need to use Flow in Room, you know I only want the entities once mostly, could you tell me?
Code C
@Dao
interface RecordDao {
@Query("SELECT * FROM record_table ORDER BY createdDate desc")
fun listRecord(): Flow<List<RecordEntity>>
}
Code D
@Dao
interface RecordDao {
@Query("SELECT * FROM record_table ORDER BY createdDate desc")
suspend fun listRecord(): List<RecordEntity>
}
collect
function suspends forever. It never resumes. So any code you put after collect
will never be executed. This is the problem with Code A.
If you want to make code A work, you should collect each flow in a separate coroutine using the launch
function.
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)
}
Also, you need not switch Dispatchers in the code, Room does that automatically.
Edit: If you need to get the list of RecordEntity
only once, code D is a better approach. Flow
is required when we need to observe the changes in the query result. For example, while displaying a list of RecordEntity
in the UI, we would want to update the UI if the data in database changes and for that we can return Flow
from Dao.
For your particular case, you can do this:
@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)
}