Home > other >  Why can't the emit() operation of Flow after emitAll() be launched in Kotlin ? and onCompletion
Why can't the emit() operation of Flow after emitAll() be launched in Kotlin ? and onCompletion

Time:04-06

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.

  • Related