https://kotlinlang.org logo
Join the conversationJoin Slack
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by Linen
coroutines
  • g

    George

    06/01/2022, 3:35 PM
    Hi folks, question: Any real difference for this:
    override fun encode(
        inputStream: Publisher<out Any>,
        bufferFactory: DataBufferFactory,
        elementType: ResolvableType,
        mimeType: MimeType?,
        hints: MutableMap<String, Any>?
    ): Flux<DataBuffer> {
       1) return Flux.from(inputStream).map { bufferFactory.wrap(protobufSerializer.encodeToByteArray(elementType)) }
       vs 
       2) return inputStream
            .asFlow()
            .map { bufferFactory.wrap(protobufSerializer.encodeToByteArray(elementType)) }
            .asFlux()
    }
    Is it worth it to keep the transformation asFlow -> map -> and then return again the Flux ?
    j
    • 2
    • 3
  • s

    Stefan Oltmann

    06/02/2022, 2:37 PM
    I look for an easy solution how I can consume a
    channel
    or
    flow
    in parallel. I don't really find something here, just a discussion on GitHub: https://github.com/Kotlin/kotlinx.coroutines/issues/172 I understood that
    flow.buffer(3).collect { action() }
    doesn't do that. What I want is receive N (N = cpu cores) entries from a collection in parallel to process them. I don't like how channel.receive() waits forever or throws an exception. What would be a simple solution for that?
    ✅ 1
    s
    c
    • 3
    • 3
  • p

    Paul Woitaschek

    06/03/2022, 6:38 AM
    How can I do non blocking side effects? Let’s say I have a search flow and on each emission I want to call a suspending track function but it should not delay the flow itself.
    val search = MutableStateFlow("")
    
    suspend fun track(query: String) {
        delay(1000)
        println(query)
    }
    
    runBlocking {
        search
            .onEach { track(it) }
            .map {
                "The search is $it"
            }
            .collectLatest {
                println("Collected $it")
            }
    }
    In onEach I could launch a coroutine on a scope and store the job to cancel the previous tracking action but is there a better solution for that?
    e
    g
    +2
    • 5
    • 9
  • c

    Colton Idle

    06/03/2022, 8:08 AM
    I'm working on an Android app, and in my VM I have an init {} block with 3 separate "inifinite" collect {} calls. viewModelScope.launch { launch { service.flow1().collect { } } launch { service.flow2(NEED an id FROM flow 1).collect { } } launch { service.flow3(NEED an id FROM flow 1).collect { } } } What would be the best way to do something like that?
    e
    f
    • 3
    • 6
  • g

    Greg Rynkowski

    06/03/2022, 6:05 PM
    Hi. I'm trying to understand basics of testing hot Flows when using
    runTest
    . Have a look at the two tests below. The first uses runBlockingTest, the other runTest.
    @Test
    fun `test shared flow with deferred`() = runBlockingTest {
        val sharedFlow = MutableSharedFlow<Int>(replay = 0)
        val deferred = async { sharedFlow.first() }
        sharedFlow.emit(1)
        assertEquals(1, deferred.await())
    }
    
    @Test
    fun `test shared flow with deferred - runTest`() = runTest {
        val sharedFlow = MutableSharedFlow<Int>(replay = 0)
        val deferred = async { sharedFlow.first() }
        sharedFlow.emit(1)
        assertEquals(1, deferred.await())
    }
    Why the second one never finish?
    e
    a
    • 3
    • 2
  • j

    Jan

    06/05/2022, 4:57 PM
    Whats the best way to download multiple files in coroutines with a fixed amount of parallel downloads. So there are like 1000 files and I want to download them in parallel but only 4 at a time
    t
    j
    +3
    • 6
    • 5
  • g

    Gabi

    06/05/2022, 8:18 PM
    Hello, anyone can help me with this error?
    Exception in thread "DefaultDispatcher-worker-6 @track-session/cu#80" java.lang.NullPointerException: Cannot invoke "kotlinx.coroutines.flow.Flow.collect(kotlinx.coroutines.flow.FlowCollector, kotlin.coroutines.Continuation)" because "this.$this_unsafeTransform$inlined" is null
    	at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1.collect(SafeCollector.common.kt:113)
    	at kotlinx.coroutines.flow.FlowKt__CollectKt.collect(Collect.kt:30)
    	at kotlinx.coroutines.flow.FlowKt.collect(Unknown Source)
    	at gragas.play.TrackSession.playRegisteredTracks(TrackSession.kt:117)
    	at gragas.play.TrackSession.access$playRegisteredTracks(TrackSession.kt:38)
    	at gragas.play.TrackSession$3.invokeSuspend(TrackSession.kt:58)
    	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
    	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
    	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
    	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
    	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [CoroutineName(track-session/cu), CoroutineId(80), "track-session/cu#80":StandaloneCoroutine{Cancelling}@6465a67d, Dispatchers.Default]
    This is the source of playRegisteredTracks
    private suspend fun playRegisteredTracks() {
      queue
        .onEach { song ->
          player.playTrack(song)
        }
        .collect()
    }
    And this is the full source of TrackSession.kt https://gist.github.com/2cc063411159091c45c3a3e1d4cc8155
    n
    • 2
    • 3
  • e

    Exerosis

    06/06/2022, 4:05 AM
    Can you have multiple continuation interceptors?
    z
    • 2
    • 4
  • r

    Robert Kempton

    06/06/2022, 4:32 PM
    I have about 1 million tasks that I need to complete. I would like to run 20 of them concurrently, and schedule them in batches of 1000. I'm looking at using newFixedThreadPoolContext, but I'm not sure that's correct, and the DelicateCouroutinesApi warning has me feeling unsure about it. What is an appropriate way to achieve this using coroutines?
    a
    j
    e
    • 4
    • 9
  • t

    Trey

    06/06/2022, 9:41 PM
    Is there a reason why a coroutine lambda wouldn't be executed after launch is called on it? I have a KMP project and on iOS, the launch function is called, but the lambda isn't executed. I'm pulling at threads trying to figure out why this isn't working. I don't have any errors in my project when ran.
    j
    • 2
    • 7
  • l

    Lucas

    06/07/2022, 10:22 PM
    Anyone knows how to fix this? Compiles and runs file
    j
    • 2
    • 1
  • m

    myanmarking

    06/08/2022, 1:41 PM
    is this allowed:
    withContext(<http://Dispatchers.IO|Dispatchers.IO> + NonCancellable)
    :yes-black: 4
    s
    s
    • 3
    • 5
  • u

    uli

    06/09/2022, 4:32 PM
    I have the following code to expose SharedPreferences changes as kotlin flow. As I want to use the flow to initialize UI it should start by emitting the current value of the SharedPreference immediately.
    fun <V : Any> SharedPreferences.asFlow(
        key: String,
        defaultValue: V?,
        retrieve: SharedPreferences.(String, V?) -> V?,
    ): Flow<Optional<V>> {
        return callbackFlow {
            val prefsListener = SharedPreferences
                .OnSharedPreferenceChangeListener { sharedPreferences, k ->
                    if (k == key) {
                        val value = sharedPreferences.retrieve(key, defaultValue)
                        trySendBlocking(value.asOptional())
                    }
                }
            registerOnSharedPreferenceChangeListener(prefsListener)
            awaitClose {
                unregisterOnSharedPreferenceChangeListener(prefsListener)
            }
        }
            .onStart {
                emit(Optional.ofNullable(retrieve(key, defaultValue)))
            }
            .distinctUntilChanged()
    As it looks, this code is racy, if shared preferences are changed after
    onStart
    emits, but collecting of the callbackFlow has not yet started. Anyone has any hints on an elegant solution to this? Like a way to start collecting the callback flow immediately, but still injecting a first element?
    t
    j
    m
    • 4
    • 32
  • l

    Lukas Lechner

    06/10/2022, 10:41 AM
    Created a new video, maybe it is helpful for someone: 5 common mistakes when using Kotlin Coroutines 👇

    https://youtu.be/coq9XDMB-yU▾

    👍🏼 1
    👍🏽 1
    👍🏾 1
    👍 5
    j
    • 2
    • 1
  • m

    Michal Klimczak

    06/13/2022, 6:15 AM
    I'm trying to understand the subtleties of new test dispatchers and I'm not sure about the never ending coroutine handling. I have 3 test cases, why the third one passes? 🧵
    t
    • 2
    • 3
  • j

    juliocbcotta

    06/13/2022, 7:06 AM
    what is the correct way to integrate coroutines in a context where we don't control the API we are integrating with? For instance, in a okhttp interceptor which has a sync API, I would like to read a database entry using coroutines. My first thought was
    runBLocking
    , but I everybody says we shouldn't be using that, so what should I be using?
    j
    y
    +2
    • 5
    • 24
  • m

    Michal Klimczak

    06/13/2022, 8:50 AM
    And another difference between standard and unconfined test dispatchers which is difficult to understand for me:
    fun test() = runTest(UnconfinedTestDispatcher(), dispatchTimeoutMs = 200) {
                val scope = this
                val counter = MutableStateFlow(0)
                counter.test {
                    awaitItem() shouldBe 0
                    scope.launch {
                        counter.value = 1
                        counter.value = 0
                    }
                    awaitItem() shouldBe 1
                    awaitItem() shouldBe 0
                }
            }
    This code will run fine on
    StandardTestDispatcher
    but will time out on
    UnconfinedTestDispatcher
    . It's not flakiness, it will time out every single time, so I assume it's a difference between the two dispatchers.
    e
    r
    • 3
    • 19
  • c

    Cody Mikol

    06/13/2022, 1:44 PM
    In kotlin, if you have
    scope.launch {
      fooSuspendedFun()
      barSuspendedFun()
    }
    will barSuspendedFun wait until the completion of fooSuspendedFun, or do you need to use something to await the return of the first function?
    j
    e
    • 3
    • 4
  • w

    Will Henry

    06/13/2022, 9:22 PM
    I have been dealing with an intermittent coroutine related issue for some time now in my Spring Boot server project. I have a custom coroutine scope:
    class AppIOCoroutineScope : CoroutineScope by CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>)
    When I receive a webhook from an external service, I create a background job like:
    appIOCoroutineScope.launch {
      // do the work
    }
    Eventually, the coroutine never launches. The first line in the launch block is a log statement which I do not see in my logs when I detect that this job isn't running. A server restart always fixes the issue. I've taken various thread dumps at this point and nothing has stuck out to me like the usual deadlocks. Are there any coroutine debug tools that I can use to better understand what's going on here?
    m
    d
    • 3
    • 2
  • e

    Exerosis

    06/14/2022, 9:11 AM
    Can someone help me understand how to handle cancellation here properly?
    context(Toggled) @Base
    suspend fun simultaneously(
        context: CoroutineContext = EmptyCoroutineContext,
        block: suspend CoroutineScope.() -> (Unit)
    ) {
        val current = currentCoroutineContext()[ContinuationInterceptor]!! + context
        val scope = object : CoroutineScope { override val coroutineContext = current }
        var task: Job? = null
        onEnabled { task = scope.launch(context) { block() } }
        onDisabled {
            println("Children: ${task?.children?.count()}")
            println("Active: ${currentCoroutineContext()[Job]?.isActive}")
            try {
                task?.cancelAndJoin(); task = null
            } catch (reason: Throwable) {
                reason.printStackTrace()
            }
            println("Active: ${currentCoroutineContext()[Job]?.isActive}")
        }
    }
    The issue is that onDisable callback is SOMETIMES called by code in
    block
    which causes cancelAndJoin() to throw cancellation exception. I figure that if I just catch it and finish letting the disable listeners get called that would be bad... since for example if another disable listener suspends execution it won't be able to return to executing state since it's job is no longer active. But I'm not sure how else I can make sure that the call which is causing cancellation is allowed to complete before it's actually done. Hopefully, that makes some sense.
    j
    • 2
    • 3
  • m

    Mattias Flodin

    06/14/2022, 1:47 PM
    In a product of ours we have had many performance issues connected to the network latency between application and database server. There are many trivial SQL queries executed in sequence and for each query there's a network round trip. Critically the database only permits a single query at a time on a given connection / transaction so I can't hide the latency by running the queries in parallel. Instead of "real" parallel execution I had an idea to develop a coroutine dispatcher that allows each coroutine to issue a query, but it queues them up and sends them in a single batch (one call to Statement.execute() with multiple statements or using executeBatch()). Each query is associated with the continuation that will process its results, so once the result sets come in I can dispatch them all through multiple resumeWith() calls. My problem is, how do I know when to stop waiting for more queries to be queued up and actually make the JDBC call? Can the coroutine dispatcher somehow detect when await() is called (or there is an implicit wait) on any of its queued continuations? Basically I want to continue queuing queries up until the originating control flow enters a waiting state.
    a
    j
    m
    • 4
    • 26
  • e

    Edwar D Day

    06/15/2022, 6:28 AM
    I have a list of `Flow`s of nullables and I would like to combine them in a way, that I only observe the second Flow, when the first one emits a
    null
    . I thought of something like that (for 2 `Flow`s):
    fun <T : Any> takeFirstNotNull(flow1: Flow<T?>, flow2: Flow<T?>): Flow<T?> {
        return flow1.transform {
                if (it != null) emit(it) else emitAll(flow2)
        },
    }
    Is there a simpler solution for this (especially, if this might be done for more `Flow`s)?
    j
    • 2
    • 11
  • j

    jmfayard

    06/16/2022, 6:26 AM
    Suspending functions + unit tests An important piece of my code was buggy but covered by a correct test ... that was ignored because I mistakenly use a suspending function in a JUnit class Gosh it would be so much better if suspending functions were supported directly in Junit instead of the
    runTest { ... }
    hack The issue is there https://github.com/junit-team/junit5/issues/1914 but very little happened since 3 years I created an issue, please star ⭐️ https://youtrack.jetbrains.com/issue/KT-52818/Provide-a-quick-fix-against-using-suspending-functions-in-Unit-Test
    s
    e
    • 3
    • 9
  • j

    juliocbcotta

    06/16/2022, 1:59 PM
    if a have a this
    myScope (supervisor + Main + interceptor)
    
    myScope.launch {
      text = mySusFunc()
    }
    
    suspend fun mySusFunc(): String {
    return withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
              delay(1000)
             "myValue"
      }
    }
    Would the attribution
    text =
    always happen in the Main ? Because from some experimenting here, it looks like it happens from the IO thread. Help ?
    j
    s
    • 3
    • 21
  • k

    Ky

    06/16/2022, 3:12 PM
    Hey guys, is there a way to set SqlDelights 'asFlow' to run on a particular dispatcher? I'm having trouble with unit tests and I think this may be the culprit
    s
    j
    • 3
    • 4
  • m

    mng

    06/16/2022, 4:59 PM
    Hey everyone, I need help with putting something together but I’m not too sure how to do so. • I want to make 2 API calls in parallel (Call A and Call B) • If Call A finishes first and is Successful, cancel Call B then return result of Call A • If Call B finishes first and is Successful, cancel Call A then return result of Call B I currently have something like this:
    val callA = async { the call }
    val callB = async { the call }
    
    if (callA.await().isSuccess) {
         callB.cancel()
         return callA.await()
    }else {
         callA.cancel()
         return callB.await()
    }
    However, it doesn’t quite get the behavior I want because I’m essentially only waiting for Call A to complete first before I even check on Call B. Can anyone offer some advice, please?
    a
    j
    n
    • 4
    • 5
  • p

    Philipp Kleber

    06/17/2022, 11:46 AM
    Hi, I want to tranform a flow to a disposable/closeable value and automatically close/dispose each transformed value as soon as a new value is emitted or the flow completes. I have come up with the following implementation of this behavior:
    @OptIn(ExperimentalCoroutinesApi::class)
    inline fun <T, S> Flow<T>.mapDisposable(
        crossinline transform: suspend (value: T) -> S,
        crossinline onDispose: (S) -> Unit
    ) : Flow<S> {
        return flatMapLatest { value ->
            callbackFlow {
                val transformed: S = transform(value)
                trySend(transformed)
                awaitClose {
                    onDispose(transformed)
                }
            }
        }
    }
    Is there a better or even a built-in way for achieving this?
    n
    • 2
    • 1
  • t

    tylerwilson

    06/17/2022, 1:18 PM
    Any plans for a 1.6.2-native-mt build?
    j
    h
    • 3
    • 3
  • d

    Doru N.

    06/17/2022, 2:16 PM
    Hey guys, I have a question regarding coroutines flow. I have a typical Repository use case where I would like to return a Flow<List<Something>> of data (in memory cache), but when that data is empty, I need to get (and store) from somewhere else (Remote), so for following collectors, I should replay the same value, and not call remote again. I was searching for a Flow function that would help me with that, but I need to make the Flow collectors wait so the remote call should be done only once. Is there an easy way to achieve this? What I tried:
    class Repository {
    	private val idsFlow = MutableStateFlow<List<String>>(emptyList())
    
    	fun getMyFlow(): Flow<List<String>> = idsFlow.onSubscription { 
    		if (idsFlow.value.isEmpty() idsFlow.value = getRemoteIds()) 
    	}
    
    	private suspend fun getRemoteIds(): List<String> {
    		delay(2_000)
    		return listOf("1", "2")
    	}
    
    	.. 
    	// other functions that can modify myFlow (ie. add / delete / update an item from it)
    }
    problem is, if multiple collectors are subscribing fast enough, getRemoteData gets called multiple times (which I want to avoid).
    s
    n
    • 3
    • 3
  • e

    Exerosis

    06/18/2022, 4:50 PM
    What is the point of CoroutineStart? How does Android avoid deadlocks if Dispatchers.Main isn't the same as Dispatchers.Main.immediate? What is the deal with Atomic starts and unconfined executing if they are already canceled? What abstraction is afforded by CoroutineDispatcher, ContinuationInterceptor etc.? It seems like functions like yield, continuation.intercepted(), etc. invalidate all of that by only being compatible only with specific dispatcher implementations. Is it possible to safely make a job that cancels and then becomes no longer canceled later? Why does Dispatchers.Unconfined have an event loop and in the example:
    withContext(Dispatchers.Unconfined) {
       println(1)
       withContext(Dispatchers.Unconfined) { // Nested unconfined
           println(2)
       }
       println(3)
    }
    println("Done")
    Not always print 1, 2, 3 shouldn't the existence of the unconfined dispatcher have 0 impact on a block of code that doesn't make suspending calls? Is it possible for withContext to modify the way something executes if you aren't inserting a different dispatcher? What is the meaning of:
    The invocation of cancel with exception (other than CancellationException) on this supervisor job also cancels parent.
    Isn't is the case that every "well formed" call to cancel has either a CancellationException or null? Does that mean cancel() doesn't cancel parent but cancel(CancellationException()) does? Is that a standard understanding for jobs? Very much struggling to understand how to adapt all of this to my system in an "idiomatic" way.
    n
    • 2
    • 10
Powered by Linen
Title
e

Exerosis

06/18/2022, 4:50 PM
What is the point of CoroutineStart? How does Android avoid deadlocks if Dispatchers.Main isn't the same as Dispatchers.Main.immediate? What is the deal with Atomic starts and unconfined executing if they are already canceled? What abstraction is afforded by CoroutineDispatcher, ContinuationInterceptor etc.? It seems like functions like yield, continuation.intercepted(), etc. invalidate all of that by only being compatible only with specific dispatcher implementations. Is it possible to safely make a job that cancels and then becomes no longer canceled later? Why does Dispatchers.Unconfined have an event loop and in the example:
withContext(Dispatchers.Unconfined) {
   println(1)
   withContext(Dispatchers.Unconfined) { // Nested unconfined
       println(2)
   }
   println(3)
}
println("Done")
Not always print 1, 2, 3 shouldn't the existence of the unconfined dispatcher have 0 impact on a block of code that doesn't make suspending calls? Is it possible for withContext to modify the way something executes if you aren't inserting a different dispatcher? What is the meaning of:
The invocation of cancel with exception (other than CancellationException) on this supervisor job also cancels parent.
Isn't is the case that every "well formed" call to cancel has either a CancellationException or null? Does that mean cancel() doesn't cancel parent but cancel(CancellationException()) does? Is that a standard understanding for jobs? Very much struggling to understand how to adapt all of this to my system in an "idiomatic" way.
n

Nick Allen

06/18/2022, 7:30 PM
Coroutine start let’s you define lazy async coroutine that doesn't cost you anything unless and until you need it (maybe a web request) or an atomic coroutine that is taking over responsibility of a resource (file or socket?) you need to close so it at least needs to actually start in order to close the resource if nothing else.
Why would android deadlock from the main dispatchers?
The continuation interceptor is built into the stdlib. Dispatchers are in the coroutines library and provide extra functionality that the library relies on. A completely different coroutine library (anyone could write one) would still presumably use the interceptor.
The point of yield is to let other coroutines run, if there's no other coroutine…then there’s nothing for it to do. That's not “invalid”. It’s kind of a waste that some dispatchers suspend in this scenario, just to resume the same coroutine, but it's really an implementation detail on how easy or difficult it is to detect that scenario.
The example code is just wrong for what’s trying to be explained. That code will always print the same thing no matter what implementation is used. Replace the second withContext with launch, then it'll actually make some sense. Does the dispatcher run launched code first or queue it up for later? That’s an implementation detail.
The doc linking to cancel is out of date. Any throwable used to work but that overloads was deprecated. The point that comment is trying to make is that it ignores child failures, but if it fails itself, then that failure is not ignored and propagates up.
e

Exerosis

06/22/2022, 12:59 AM
Sorry for the delay @Nick Allen thanks for clearing so many things up! I'll look into lazy starts more, I'm not sure I understand when the lazily started coroutines actually run at all. What is the point of undispatched if atomic exists then? Android could deadlock in this situation (presumably):
specialCancellableButtonOrSomething.onClick { event ->
  if (!runBlocking(Dispatchers.Main) { someCallbackOrSomething() })
    event.cancel()
}
Because the button onClick is on the main thread and so if we dispatch is going to schedule a task rather than running the task right away on the current thread (immediate) then until the onClick listener returns the someCallbackOrSomething() cannot be dispatched... However the onClick listener cannot return until after it has been (deadlock). Couldn't you just give dispatchers canYield and yield() or just yield and they suspendUninterceptedOrReturn where they internally return if they cannot yield and suspend if they can? IG I still don't understand properly or something. Ah yes launch would make more sense. If I understand correctly the thread responsible for running launched tasks is either what thread resumes the withContext, or the thread that called launch. Thanks again!
n

Nick Allen

06/22/2022, 2:09 AM
For lazy:
val result = myScope.async(start = CoroutineState.Lazy) { //doesn't run
    println("running")
    delay(100)
    42
}
delay(1000) //still doesn't run
println("result=${result.await()}") //now it'll start, wait 100, and then we'll print "result=42" 1100 millis after the coroutine was created
println("again, result=${result.await()}") //Will print immediately, it only runs once
Undispatched is more of an optimization, to avoid unnecessary thread switches. It takes extra time to schedule and wait for the scheduled task to actually run. It's extra convenient when you know you are already on the dispatcher you want. You should not be calling
runBlocking
from a click listener. It blocks which you should never do on main thread. Even if passing in other dispatchers. You can launch a coroutine using Dispatchers.Main and then you get the benefits of coroutines and can modify UI elements. runBlocking is more for APIs like OkHttp that have a private thread pool and then invoke callbacks on that thread pool expecting you to block so runBlocking is ok. Of course they could have designed yield differently to always suspend ... but why? It does what it's supposed to do which is pass control back to the dispatcher. If you describe your usecase, then I can probably redirect you to the right API to use.
e

Exerosis

06/23/2022, 1:11 AM
But how can you avoid using runBlocking when you are implementing systems? Obv the ideal situation is one where the onClick listener itself is a suspend fun and then there is no issue, but when you interface with java applications and frameworks you often don't have a choice. For example, if you launched in the onClick listener then you could not modify the click event in any way. I don't have a usecase in mind for yield right now, I was just curious as to why there was so much casting going on behind the scenes.
n

Nick Allen

06/23/2022, 3:51 AM
If you need to do something in the click event, you do it immediately before starting your async/background work. If your design requires you to wait for async/background processing and then do something in the click event, your design is inherently broken and needs to be revised. This as true for
runBlocking
as it is for
Future.get
.
View count: 24