https://kotlinlang.org logo
#coroutines
Title
# coroutines
f

FunkyMuse

01/25/2021, 10:43 AM
Hi everyone, how do you use coroutines to tackle with the SingleLiveEvent I've tried the code below but when rotating the device the latest value is displayed, i want the value to be consumed only once just as SingleLiveEvent is
Copy code
protected val loadingState = BroadcastChannel<Boolean>(Channel.BUFFERED)
    val actionReceiver = loadingState.asFlow()
s

Shalom Halbert

01/25/2021, 2:37 PM
SharedFlow
is what you want to use
a

Adam Powell

01/25/2021, 3:42 PM
If you want only a single consumer to receive something you send, use
Copy code
val loadingChannel = Channel<Boolean>(Channel.BUFFERED)
val loadingFlow = loadingChannel.receiveAsFlow()
send to
loadingChannel
and observe using
loadingFlow
.
f

FunkyMuse

01/25/2021, 3:42 PM
I tried that but when the rotation happens the last value is emitted
I even tried consumeAsFlow since it happens only once
a

Adam Powell

01/25/2021, 3:43 PM
If you use
Channel.receiveAsFlow
then no value will be emitted more than once. Are you sure your other code isn't sending to the channel more than once?
f

FunkyMuse

01/25/2021, 3:44 PM
I'll check that and post the code if i don't find any solution, I'm literally trying to replace SingleLiveEvent
a

Adam Powell

01/25/2021, 3:45 PM
it's good to replace SingleLiveEvent, it's a workaround for a problem that doesn't exist with coroutines/channels/flows 🙂
but SingleLiveEvent encourages some other antipatterns around working with state and events. You may need to resolve those to move forward in an elegant way if they've crept into your codebase.
f

FunkyMuse

01/25/2021, 3:47 PM
My use case is this User clicks download Download event success or fail (update ui only once) Which I've habdled with single live event before
a

Adam Powell

01/25/2021, 3:57 PM
yes, this is where clearly separating state and events helps clarify the design. Events happen only once. State is updated by events, and current state can be observed at any time, as many times as desired. Reacting to state updates is always idempotent, so there's no need to think of it as, "updating UI only once." UI update observers update the UI to match the state with no other side effects. Any one-time side effects of the download complete event should happen as part of observing the one-time download complete event and setting the download completed state used by the UI updaters.
f

FunkyMuse

01/25/2021, 9:39 PM
In my view model i had val loadingChannel = Channel<Boolean>(Channel.BUFFERED) val loadingFlow = loadingChannel.receiveAsFlow() And in my fragment viewLifecycleOwner.lifecycleScope.launcWhenResumed{ viewModel.loadingFlow.collect{ //Some logic here } } Inside my logic i didn't receive anything I tried loadingChannel.offer(true) // and false Am I doing something wrong?
a

Adam Powell

01/26/2021, 12:05 AM
did you check that the
launchWhenResumed
block runs as expected, before the
collect
call begins?
f

FunkyMuse

01/26/2021, 10:48 AM
Yes it runs since i have another StateFlow collecting the list
Found the problem
message has been deleted
This did not work
whilst this did work
message has been deleted
Copy code
val Fragment.viewCoroutineScope get() = viewLifecycleOwner.lifecycle.coroutineScope
weird, both are suspending functions btw
o

Oleksandr Balan

01/26/2021, 1:02 PM
I believe it’s due to
collectSubtitles
is blocking. I bet you start to collect a
Flow
there 🙂
f

FunkyMuse

01/26/2021, 1:02 PM
yes i did
how do i fix it?
if i use
Copy code
.onEach{}.launchIn(scope)
and put it inside the onResumed block, would it be called in onResume since it's launched in the scope with launchIn?
a

Adam Powell

01/26/2021, 3:05 PM
You can wrap each of the two calls that you want to run concurrently in their own
launch
inside a single
launchWhenResumed
Copy code
...launchWhenResumed {
  launch { collectSubtitles() }
  launch { handleDownloadStatus() }
}
f

FunkyMuse

01/26/2021, 3:07 PM
That's more than i needed, it's clear to me now, thanks Adam 🍺
👍 1
o

Oleksandr Balan

01/26/2021, 3:16 PM
But there is no big difference between
Copy code
scope.launchWhenResumed {
   launch { collectSubtitles() }
   launch { handleDownloadStatus() }
}
and
Copy code
scope.launchWhenResumed { collectSubtitles() }
scope.launchWhenResumed { handleDownloadStatus() }
?
a

Adam Powell

01/26/2021, 9:18 PM
the former is a bit more efficient
👌 1
3 Views