Rick
11/26/2019, 7:01 AMhikkidev
11/26/2019, 7:16 AMtseisel
11/26/2019, 9:56 AMFlow
. I have a source flow the emits the current result of a request in database whenever it changes (like a Flow
returned by Android Room). I decided to expose the result of those request with a repository.
interface DataSource {
val flow: Flow<List<Foo>>
}
class Repository(
private val source: DataSource
)
val diff: Flow<Diff<Foo>> get() = TODO()
suspend fun getLatest(): List<Foo> = TODO()
}
How can I transform the source flow to adapt it to the needs of the Repository
? (The Diff
is calculated from the latest and the previous list of `Foo`s.)
Is it possible to cache the latest value just like Android LiveData
, to avoid costly database queries when repeateadly reading the latest values ?dave08
11/26/2019, 1:23 PMval dispatcher = Dispatchers.Main.immediate
val scope = CoroutineScope(dispatcher)
fun main() {
println("Started.")
scope.launch { delay(30); println("Hi!") }
println("Finished.")
}
dave08
11/26/2019, 1:29 PMyield()
)?Robert Jaros
11/26/2019, 2:03 PM1.3.2-1.3.60
the official release of coroutines for kotlin 1.3.60 ?deviant
11/26/2019, 2:54 PMtseisel
11/27/2019, 1:09 PMReceiveChannel<T>.onReceiveOrNull
has been deprecated, it is suggested to replace it with the onReceiveOrNull
extension function.
But I find that it's surprisingly hard to use that function:
1. Since there is a member property onReceiveOrNull
it takes precedence over the extension.
2. Since onReceiveOrNull
is a function, the block passed as select clause is incorrectly interpreted as an extra lambda parameter.
While the following workaround code works:
import kotlinx.coroutines.channels.onReceiveOrNull as onReceiveOrNullExt
select {
channel.onReceiveOrNullExt().invoke { foo ->
[...]
}
anotherChannel.onReceive { bar ->
[...]
}
}
It is not as convenient as the original Select API.
Wouldn't it be better to convert that extension function to an extension property with a different name ?jimn
11/27/2019, 7:55 PMspand
11/28/2019, 9:31 AMFileReader
to suspend. Does this look good?
• Should I cancel the continuation when the underlying resource is aborted (ie. by the browser) ?
• Is this sequence safe ? continuation.invokeOnCancellation -> abort() -> onabort -> continuation.cancel()
suspend fun Blob.readAsDataUrl2(): String {
val fileReader = FileReader()
return suspendCancellableCoroutine { continuation ->
fileReader.onload = {
val dataUrl = fileReader.result as String
continuation.resume(dataUrl)
}
fileReader.onerror = {
continuation.resumeWithException(DomExceptionThrowable(fileReader.error as DOMException))
}
fileReader.onabort = {
continuation.cancel()
}
continuation.invokeOnCancellation { fileReader.abort() }
fileReader.readAsDataURL(this) // <-- Async work starts here
}
}
bnn
11/29/2019, 4:03 AMsuspend fun foo(): Foo {
return runCatching {
// do something with calling other suspend functions
Foo()
}.getOrElse { exception ->
// do somethiing
Foo()
}
}
The code example above will not propagate CancellationException to caller.
Is it OK?
Or would I better to consider propagate CancellationException, like
suspend fun foo(): Foo {
return runCatching {
// do something with calling other suspend functions
Foo()
}.getOrElse { exception ->
if (exception is CancellationException) {
throw exception
}
// do something
Foo()
}
}
In my opinion, suspend functions are better to propagate CancellationException.
But, when we use runCatching inside it, there might be kind of boilerplate like above. Are there idiomatic ways to handle coroutines cancellation with runCatching. Or should I avoid to use it inside suspend function?Jordi Saumell
11/29/2019, 8:30 AMPaul Woitaschek
11/29/2019, 12:38 PMclass MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
CoroutineScope(SupervisorJob() + Dispatchers.Main).launch {
while (true) {
combine(flowOf(Unit), flowOf(Unit)) { _ -> Unit }.collect()
}
}
}
}
This leads to a sigsegv
Flags: 0x28c8bf46
Package: com.example.weirdcrash v1 (1.0)
Foreground: Yes
Build: TCL/5009D/U5A_PLUS_3G:7.0/NRD90M/5009D_ALWE_V2.9_20180529:user/release-keys
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'TCL/5009D/U5A_PLUS_3G:7.0/NRD90M/5009D_ALWE_V2.9_20180529:user/release-keys'
Revision: '0'
ABI: 'arm'
pid: 29639, tid: 29639, name: mple.weirdcrash >>> com.example.weirdcrash <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x15608
r0 00015000 r1 12d35700 r2 00000002 r3 00000000
r4 af58a6d8 r5 12d31ee0 r6 12d37280 r7 00000000
r8 12d35700 r9 ac684400 sl 12cb0a90 fp 12d33bf8
ip bef2f84c sp bef2f8b0 lr 9901f5ef pc 9901f608 cpsr 000f0030
backtrace:
#00 pc 00000608 /dev/ashmem/dalvik-jit-code-cache (deleted)
#01 pc 000005ed /dev/ashmem/dalvik-jit-code-cache (deleted)
29639
I currently see about 1200 affected users; is there anythign I can do here?Colton Idle
11/29/2019, 10:25 PMviewModelScope.launch {
val userProfileResponse = apiManager.client!!.getProfile()
if (userProfileResponse.isSuccessful) {
_viewState.value = _viewState.value?.copy(isLoading = false, profile = userProfileResponse.body())
} else {
Log.e(TAG, "Not success")
}
}
and it works!
BUT
I tried to run the app in airplane mode and it crashes. If I use a try catch it won't crash, but I'm confused by why the IDE doesn't force me to have a try/catch. Does anyone know why?william
12/01/2019, 4:04 AMAlexjok
12/01/2019, 9:14 AMorafaaraujo
12/02/2019, 10:29 AMBroadcastChannel
out of a Coroutine
?Dominaezzz
12/02/2019, 3:53 PMsealed class Tree {
data class Parent(val children: List<Tree>): Tree()
data class Leaf(val value: Int): Tree()
}
fun Tree.simpleSum(): Int {
return when (this) {
is Tree.Parent -> children.map { it.simpleSum() }.sum()
is Tree.Leaf -> value
}
}
fun Tree.concurrentSum(): Int {
return when (this) {
is Tree.Parent -> runBlocking {
children.map { async { it.simpleSum() } }
.awaitAll().sum()
}
is Tree.Leaf -> value
}
}
suspend fun Tree.questionableSum(): Int {
return when (this) {
is Tree.Parent -> coroutineScope {
children.map { async { it.questionableSum() } }
.awaitAll().sum()
}
is Tree.Leaf -> value
}
}
I basically want to sum up all the nodes in the tree. Right now I create a Job
for every immediate child of the root (concurrentSum
), but I might not be using all the parallelism available. I'm tempted to recursively create a Job
at every node (questionableSum
) which would use all the parallelism but I get the feeling that that's not the way to go.
Is there a "right" way to go about this?Jordi Saumell
12/02/2019, 4:20 PMorafaaraujo
12/03/2019, 10:24 AMFlow
still experimental on 1.3.2
?
Tha changelog says that is not but my AS keep me asking to put @ExperimentalCoroutinesApi
Ruckus
12/03/2019, 4:59 PMlaunch { field.setAs { calculate() } }
...
private fun StringProperty.setAs(calc: () -> Any) = set(
try {
calc().toString()
} catch (e: Exception) {
e.message
}
)
(Note that setAs
has no suspension at all)
But if calc
throws an exception, it isn't caught and instead just crashes. Am I missing something obvious?Luke Rohde
12/03/2019, 6:25 PMflow {
for (i in collection) {
try {
emit(i)
} finally {
doCleanupOn(i)
}
}
}
is there a better way to accomplish this?itnoles
12/03/2019, 8:04 PMIve Vasiljevic
12/04/2019, 1:22 PMfun main() = runBlocking {
val job = launch {
println("Coroutine start")
launch {
println("Child coroutine start")
println("Child coroutine end")
launch {
println("Child-inner coroutine start")
println("Child-inner coroutine end")
}
}
println("Coroutine end")
println("Coroutine end!")
}
println("Join")
println("Done")
}
Why is Join and Done executed before job? And when calling job.join() between println("Join") and println("Done") job is executed at the place of calling job.join()?Gabriel Machado
12/04/2019, 1:35 PMsuspend
functions always Object
when compiled?Tucker Barbour
12/04/2019, 3:44 PMrunBlocking {
val channel = Channel<Int>(bufferSize)
val producers = (0..producerCount).map { launch { produceValues(channel) } }
while (producers.any { it.isActive }) {
// time-of-check time-of-use race condition here. If there were any producers active at the time of check but had finished sending messages, we end up waiting on messages that we'll never receive
val message = channel.receive()
doSomethingWithMessage(message)
}
coroutineContext.cancelChildren()
}
If I were using Java I would probably use a CountdownLatch to coordinate the completion of the Producers with the Consumers. Is there a similar pattern for coroutines?ApplePeel
12/05/2019, 10:42 AMVsevolod Ganin
12/05/2019, 11:06 AMCoroutineExceptionHandler
installed in top-most runBlocking
is not being called? I read all docs but can’t quite grasp the sense of it. Example:
fun main(): Unit = runBlocking(CoroutineExceptionHandler { _, e ->
println("Boom: $e")
}) {
(0..10).map {
launch {
println("Throw in attempt #$it")
throw RuntimeException("Attempt #$it")
}
}
Unit
}
jimn
12/05/2019, 4:39 PMv0ldem0rt
12/05/2019, 9:33 PMv0ldem0rt
12/05/2019, 9:33 PMoctylFractal
12/05/2019, 9:34 PMrunBlocking
, async just use a CoroutineScope object (create one and make sure it has the correct lifecycle for whatever you're doing)v0ldem0rt
12/05/2019, 9:40 PM