I run Code A and get Result A as I expected, all emit operations in Code A is launched one by one.
I think all emit operations in Code B and Code C should be launched one by one, but in fact. the the emit()
operation after emitAll()
isn't launched! You can see Result B and Result C. Why?
I run Code D and get Result D as I expected, onStart{...}
is launched before return Flow.
But onCompletion{}
isn't launched in both Code E and Code F, you can see Result E and Result F, why?
Code A
@Composable
fun Greeting(
name: String,
mViewMode:SoundViewModel= viewModel()
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
LaunchedEffect(Unit) {
Log.e("My", "Start")
val s = mViewMode.listRecord()
s.collect { i ->
when(i){
is Result.Loading -> Log.e("My", "Load")
is Result.Success -> Log.e("My", "Success")
is Result.Error -> Log.e("My", "Error")
}
}
}
}
}
@HiltViewModel
class SoundViewModel @Inject constructor(
private val aSoundMeter: RecordRepository
): ViewModel()
{
fun listRecord(): Flow<Result<List<MRecord>>> {
return aSoundMeter.listRecord()
}
}
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override fun listRecord(): Flow<Result<List<MRecord>>> {
return flow {
emit(Result.Loading)
emit(Result.Error(Exception()))
val s=mRecordDao.listRecord().map { Result.Success(listEntityToModel(it)) }
emitAll(s)
}
}
}
@Dao
interface RecordDao {
@Query("SELECT * FROM record_table ORDER BY createdDate desc")
fun listRecord(): Flow<List<RecordEntity>>
}
sealed class Result<out R> {
data class Success<out T>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
object Loading : Result<Nothing>()
}
Result A
2022-04-04 18:13:12.417 25866-25866/info.dodata.soundmeter E/My: Start
2022-04-04 18:13:12.428 25866-25866/info.dodata.soundmeter E/My: Load
2022-04-04 18:13:12.429 25866-25866/info.dodata.soundmeter E/My: Error
2022-04-04 18:13:12.509 25866-25866/info.dodata.soundmeter E/My: Success
Code B
//...The same
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override fun listRecord(): Flow<Result<List<MRecord>>> {
return flow {
emit(Result.Loading)
val s=mRecordDao.listRecord().map { Result.Success(listEntityToModel(it)) }
emitAll(s)
emit(Result.Error(Exception()))
}
}
}
Result B
2022-04-04 18:15:57.980 26014-26014/info.dodata.soundmeter E/My: Start
2022-04-04 18:15:57.993 26014-26014/info.dodata.soundmeter E/My: Load
2022-04-04 18:15:58.087 26014-26014/info.dodata.soundmeter E/My: Success
Code C
//...The same
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override fun listRecord(): Flow<Result<List<MRecord>>> {
return flow {
val s=mRecordDao.listRecord().map { Result.Success(listEntityToModel(it)) }
emitAll(s)
emit(Result.Error(Exception()))
emit(Result.Loading)
}
}
}
Result C
2022-04-04 18:16:57.568 26074-26074/info.dodata.soundmeter E/My: Start
2022-04-04 18:16:57.673 26074-26074/info.dodata.soundmeter E/My: Success
Code D
//...The same
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override fun listRecord(): Flow<Result<List<MRecord>>> {
val load: Result<List<MRecord>> =Result.Loading
val data: Flow<Result<List<MRecord>>> =mRecordDao.listRecord().map { Result.Success(listEntityToModel(it)) }
return data.onStart { emit(load) }
}
}
Result D
2022-04-04 18:21:28.409 26170-26170/info.dodata.soundmeter E/My: Start
2022-04-04 18:21:28.423 26170-26170/info.dodata.soundmeter E/My: Load
2022-04-04 18:21:28.482 26170-26170/info.dodata.soundmeter E/My: Success
Code E
//...The same
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override fun listRecord(): Flow<Result<List<MRecord>>> {
val load: Result<List<MRecord>> =Result.Loading
val error: Result<List<MRecord>> =Result.Error(Exception())
val data: Flow<Result<List<MRecord>>> =mRecordDao.listRecord().map { Result.Success(listEntityToModel(it)) }
return data.onStart { emit(load) }.onCompletion { emit(error) }
}
Result E
2022-04-04 18:24:44.053 26272-26272/info.dodata.soundmeter E/My: Start
2022-04-04 18:24:44.067 26272-26272/info.dodata.soundmeter E/My: Load
2022-04-04 18:24:44.142 26272-26272/info.dodata.soundmeter E/My: Success
Code F
//...The same
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override fun listRecord(): Flow<Result<List<MRecord>>> {
val error: Result<List<MRecord>> =Result.Error(Exception())
val data: Flow<Result<List<MRecord>>> =mRecordDao.listRecord().map { Result.Success(listEntityToModel(it)) }
return data.onCompletion { emit(error) }
}
}
Result F
2022-04-04 18:25:47.395 26340-26340/info.dodata.soundmeter E/My: Start
2022-04-04 18:25:47.459 26340-26340/info.dodata.soundmeter E/My: Success
CodePudding user response:
A Flow from a Room DAO never completes. It is infinite because it monitors the database for changes forever. So when you call collect
on it (which is what emitAll
is doing internally), the function never returns and no code written under it will ever be reached. The flow will only be stopped when the coroutine that is collecting it is cancelled.