How to make kotlin flow wait till end before Terminal operator is executed

Viewed 3907
/**
* Does some work and return true to denote success
* false to denote failure
*/
suspend fun doWork(): Boolean {

    val processStatus = processWork()

    return processStatus.filter { status ->
                status == ProcessStatus.SUCCESS 
                || status == ProcessStatus.FAILURE
            }.map { filteredStatus ->
                filteredStatus == ProcessStatus.SUCCESS
            }.single()
}


/**
* Cretaes a channel in which different status will be offered
*/
suspend fun processWork(): Flow<ProcessStatus> {

    val channel = BroadcastChannel(Channel.BUFFERED)
    doThework(channel)
    return channel.asFlow()
}


/**
* Does some work in background thread
*/
fun doThework(channel: BroadcastChannel) {

    SomeSope.launch {

        //Cretae a coroutine 
        channel.offer(ProcessStatus.Status1)
        channel.offer(ProcessStatus.Status2)
        channel.offer(ProcessStatus.Status3)
        channel.offer(ProcessStatus.Status4)

        channel.offer(rocessStatus.SUCCESS)
        channel.close()
    }
}

Above is a simplified version of my code.

What I want to do is, make doWork() wait till all the values are emmited and finally return a boolean based on last ProcessStatus.SUCCESS or ProcessStatus.FAILURE.

Right now, what is happening with the above code is, as soon as the processWork() returns the flow. doWork() calls all the operators including the single() and since, the work is still in progress ProcessStatus.FAILURE or ProcessStatus.SUCCESS is still not emmited, making it give an exception.

How can I make the doWork() return statement wait and return only when the flow is Complete?


Edit 1:

Reason, I have to go with the channel is because, this is part of an Android code & the channel.offer() is not actually a new co-routine like in example above, but is being called from a Android BroadcastReceiver.

Since flow is cold, I didn't want user leaving the Activity to stop the task from being completed and notified.

1 Answers

Looks like you can use toList method to collect all values before processing them:

suspend fun doWork(): Boolean {

    val processStatus = processWork().toList()

    return processStatus.filter { status ->
                status == ProcessStatus.SUCCESS 
                || status == ProcessStatus.FAILURE
            }.map { filteredStatus ->
                filteredStatus == ProcessStatus.SUCCESS
            }.single()
}

Related