Paulius Ruminas
12/13/2019, 1:15 PM@Test
fun example() = runBlocking {
val a = produce {
var i = 0
while (isActive) {
send(i++)
delay(100)
}
}
val b = a.broadcast(start = CoroutineStart.DEFAULT)
launch {
b.consumeEach {
println("A: $it")
}
}
b.close()
delay(1_000)
}
When I close b broadcast channel I get an exception:
Exception in thread "Test worker @coroutine#3" kotlinx.coroutines.channels.ClosedSendChannelException: Channel was closed (Coroutine boundary)
Is this the expected behavior?Vsevolod Tolstopyatov [JB]
12/13/2019, 2:15 PMkotlinx.coroutines
version 1.3.3 is here!
• Dispatchers.Main
doesn’t use ServiceLoader
anymore, preventing I/O on Main thread during initialization and annoying “Module with the Main dispatcher is missing” exceptions
• Reworked Dispatchers.Default
and <http://Dispatchers.IO|Dispatchers.IO>
, CPU consumption is significantly reduced
• Flow.merge
operator
• Significant performance improvements in Flow
, Channel
and Job
classes
• Improved stacktrace recovery and debugging experience
And a lot more, full changelog: https://github.com/Kotlin/kotlinx.coroutines/releases/tag/1.3.3voben
12/13/2019, 10:49 PMoffer
or send
function to send a value to the channel and why?Anastasia Finogenova
12/14/2019, 11:08 AMrrva
12/14/2019, 11:49 AMCzar
12/14/2019, 4:08 PMsomeList.map { async { /* stuff */ }.forEach { it.await() }
My immediate reaction is to refactor it to
someList.map { async { /* stuff */ }.awaitAll()
But I see that awaitAll
allocates an array, so am I actually hurting performance instead of improving things? Is forEach { it.await() }
a more correct way to do await
on a collection of Deferred
?bjonnh
12/15/2019, 1:36 AMdave08
12/15/2019, 4:22 PMkarelpeeters
12/15/2019, 6:35 PMReceiveChannel.last()
is deprecated, it links to https://github.com/Kotlin/kotlinx.coroutines/issues/254 but what do I actually have to replace it by?karelpeeters
12/15/2019, 6:42 PMoutput.consumeEach { input.send(it) }
is correct but that's also deprecated.octylFractal
12/15/2019, 6:44 PMchan.asFlow()
firstColton Idle
12/15/2019, 7:58 PMviewLifecycleOwner.lifecycleScope.launch {
val work1 = async { getThingsDone(43) }
val work2 = async { getThingsDoneAgain(123) }
if (work1.await().isSuccessful && work2.await().isSuccessful) {
//do my thing
} else {
//failure message
}
Basically, the getThingsDone calls are retrofit network calls. If one of them is still going on and I go into airplane mode, I get a crash.
What have I tried?
1.
try {
viewLifecycleOwner.lifecycleScope.launch {
val work1 = async { getThingsDone(43) }
val work2 = async { getThingsDoneAgain(123) }
if (work1.await().isSuccessful && work2.await().isSuccessful) {
//do my thing
} else {
//failure message
}
} catch (e: Exception) {
//show failure message
}
2.
viewLifecycleOwner.lifecycleScope.launch {
try {
val work1 = async { getThingsDone(43) }
val work2 = async { getThingsDoneAgain(123) }
if (work1.await().isSuccessful && work2.await().isSuccessful) {
//do my thing
} else {
//failure message
}
} catch (e: Exception) {
//show failure message
}
}
3.
viewLifecycleOwner.lifecycleScope.launch {
val work1 : Deferred<Response<MyType>>
val work2: Deferred<Response<MyType>>
try {
work1 = async { getThingsDone(43) }
work2 = async { getThingsDoneAgain(123) }
} catch (e: Exception) {
//show failure message
}
if (work1.await().isSuccessful && work2.await().isSuccessful) {
//do my thing
} else {
//failure message
}
}
4.
viewLifecycleOwner.lifecycleScope.launch {
val work1 = async {
try {
getThingsDone(43)
} catch (e: Exception) {
//show failure message
}
}
val work2 = async {
try {
getThingsDoneAgain(123)
} catch (e: Exception) {
//show failure message
}
}
if (work1.await().isSuccessful && work2.await().isSuccessful) {
//do my thing
} else {
//failure message
}
}
I would really appreciate some help. As of now this works super nice because I essentially have two async network calls, and my code ONLY continues if both of them complete! But in the off chance that I have a network error (or force one by going into airplane mode during the request), my Android app dies.tjohnn
12/16/2019, 3:04 PMkotlinx.coroutines.channels.ClosedSendChannelException: Channel was closed
@ExperimentalCoroutinesApi
fun <T> firebaseDataAsFlow(reference: DatabaseReference) = callbackFlow {
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val type = object : GenericTypeIndicator<T>() {}
offer(dataSnapshot.getValue(type))
}
override fun onCancelled(error: DatabaseError) {
cancel(CancellationException(error.details, error.toException()))
}
})
}
The exception gets thrown whenever offer()
is calledJoseph PH
12/17/2019, 11:07 AMwithLock{...}
be applicable?Joseph PH
12/17/2019, 11:09 AMrkeazor
12/18/2019, 1:34 AMseb
12/18/2019, 7:48 AMlouiscad
12/18/2019, 10:33 AMdavid.bilik
12/18/2019, 1:58 PMoriginal function
override suspend fun user(): User {
return api.user()
}
suggested solution
var userDeferred: Deferred<User>? = null
override suspend fun user(): User {
if (userDeferred == null) {
userDeferred = async {
apiInteractor.user()
}
}
return userDeferred.await().also {
userDeferred = null
}
}
Brendan Weinstein
12/18/2019, 11:27 PMvoben
12/18/2019, 11:47 PMcolintheshots
12/20/2019, 5:08 AMrattleshirt
12/20/2019, 9:53 AMnewSingleThreadContext("io")
?Paul Woitaschek
12/20/2019, 4:41 PMThiyagu
12/20/2019, 8:51 PMbod
12/21/2019, 4:19 PMrunBlocking
... is it possible?bod
12/21/2019, 5:40 PMrunBlocking
... but now... it just freezes on iOS...ansman
12/21/2019, 8:14 PMval flow = repository
.observeStuff(id)
.map { it.map { it.createViewModel() }}
.combine(otherFlow) { stuff, otherStuff -> stuff to otherStuff }
// Don't emit until the settings are loaded
.onEach { settingsLoading.join() }
.conflate()
.flowOn(Dispatchers.Default)
.broadcastIn(viewModelScope, start = CoroutineStart.DEFAULT)
.asFlow()
scope.launch {
flow.collect {
// Rare crash because the scope is cancelled and the fragment is destroyed
view.update(it)
}
}
It really feels like it’s a bug in the coroutines framework because I can’t explain it otherwise
I can fix it by adding a yield
or if (coroutineContext[Job]?.isCancelled == true) throw CancellationException()
in my collect
but I really want to figure out what is happening. I’ve only seen it in Crashlytics
I added some logging to crashlytics to confirm the scope is cancelled:
CrashReporting.log("isStarted: %b, view == null: %b, isCancelled: %b".format(isStarted, view == null, coroutineContext[Job]!!.isCancelled))
And in the crash report is says:
isStarted: false, view == null: true, isCancelled: true
tjohnn
12/22/2019, 3:56 PMFlow.collect()
block the parent coroutine from executing the code under the flow until the flow is cancelled?
viewModelScope{
// code here get executed
someFlow.collect()
// code here never executes
}
Colton Idle
12/23/2019, 12:08 AMfromJson()
to do it's work in the background, but I don't think moshi has a suspend function for this? How would someone typically solve this?
viewModelScope.launch {
//Get from file
try {
val file = File(context.filesDir, "mycache")
val contents = file.readText()
val moshi = Moshi.Builder().build()
val jsonAdapter = moshi.adapter(MyObject::class.java)
val json = jsonAdapter.fromJson(contents)
//DO SOMETHING
} catch (e: Exception) {
} finally {
}
}
Colton Idle
12/23/2019, 12:08 AMfromJson()
to do it's work in the background, but I don't think moshi has a suspend function for this? How would someone typically solve this?
viewModelScope.launch {
//Get from file
try {
val file = File(context.filesDir, "mycache")
val contents = file.readText()
val moshi = Moshi.Builder().build()
val jsonAdapter = moshi.adapter(MyObject::class.java)
val json = jsonAdapter.fromJson(contents)
//DO SOMETHING
} catch (e: Exception) {
} finally {
}
}
octylFractal
12/23/2019, 1:05 AMwithContext(<http://Dispatchers.IO|Dispatchers.IO>) { }
fromJson
throwing IOException, as I doubt it does IO. file.readText()
probably does thoughColton Idle
12/23/2019, 1:12 AMwithContext{}
?octylFractal
12/23/2019, 1:48 AMjsonAdapter
does other things with global state that involve IO. I would guess that's not the case thoughDico
12/23/2019, 2:09 AMgildor
12/23/2019, 12:55 PMas I doubt it does IOThis warning is about blocking operation, not about only IO. Json creation is indeed potentially long operation even if it doesn't do any IO, so it make sense and it's not fooled. Wrapping to CPU bound dispatcher is not bad idea for serialization/deserialization
Colton Idle
12/24/2019, 9:16 AMgildor
12/24/2019, 9:22 AMoctylFractal
12/24/2019, 9:40 AM<http://Dispatchers.IO|Dispatchers.IO>
iirc