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
  • l

    louiscad

    03/25/2020, 11:56 AM
    People interested in, or using GraalVM, there's a dev version supporting coroutines for you to try! https://github.com/oracle/graal/issues/366#issuecomment-603767026
    🎉 1
    👍 1
    k
    • 2
    • 4
  • r

    rrva

    03/25/2020, 1:19 PM
    https://stackoverflow.com/questions/53558215/guava-loadingcache-with-kotlin-coroutines
    s
    • 2
    • 4
  • s

    Sam Garfinkel

    03/25/2020, 2:32 PM
    Is it an anti-pattern to mixin a
    CoroutineScope
    (with a delegate) on a class so that you can use
    Deferred
    as the value of its properties? This is kind of useful for creating lazily computed properties that are backed by network I/O (I’m using Ktor):
    class Foo(val client: HttpClient) : CoroutineScope by GlobalScope {
      val bar: Deferred<String> by lazy {
        async { 
          client.get<String>("<https://www.example.com>")
        }
      }
    }
    :yes: 2
    s
    a
    z
    • 4
    • 28
  • v

    vineethraj49

    03/25/2020, 5:46 PM
    what's a good naming convention if I'm writing a suspending implementation of an existing method?
    z
    z
    l
    • 4
    • 7
  • v

    vineethraj49

    03/25/2020, 5:49 PM
    what's a good way to handle jdbi handles? I'm checking if the following will work, but wanting to check if this is a "solved" problem already
    suspend fun foo() {
        val context = coroutineContext
        dbi.withHandle { conn ->
            async(context) {
                bizLogic.suspendingFunction()
            }
        }.await()
    }
    • 1
    • 1
  • m

    Maciek

    03/25/2020, 8:08 PM
    I've got a test with
    runBlockingTest
    function. From this test I'm running code that launches coroutine from
    MainScope
    object that is suppose to have
    TestCoroutineDispatcher
    but I can't seem to run
    delay
    function inside that coroutine because I'm getting
    UncompletedCoroutinesError
    exception. Is my test setup wrong or I just can't test a code that has
    delay
    functions? I don't really need that delay but was just wondering why it doesn't work, I thought that runBlocking and TestCoroutineDispatcher will take care of such cases
    d
    l
    • 3
    • 7
  • t

    thana

    03/26/2020, 10:02 AM
    i feel that coroutines have the great disadvantage, that ehy cmopletly spoil the stack traces. so currenyly im profiling an application and all i see is that
    invokeSuspend
    takes a considerbale amount of time. How do you cope with this situation? can we expect the situation will improve when the jvm itself supports suspendable methods?
    k
    d
    +2
    • 5
    • 13
  • p

    Pacane

    03/26/2020, 2:19 PM
    Hi, I'm trying to understand how to use coroutines in my use case... I am using the JVM (and not android). My code doesn't current use coroutines, I'm using Java CompleteableFuture to do async work. The type of work I'm doing is Fire and Forget type of stuff (I have an infinite while loop doing video/image processing. I currently have no
    suspend
    functions, but I could get my code to work with the
    GlobalScope.launch
    function. Now I've read in several places that I should avoid using the GlobalScope. So my question is, how can I create a coroutine scope for a given method (not the main) and still use coroutines for a fire and forget type of work. I've tried doing something like
    fun myMethod() = runBlocking { .... }
    and then inside use
    CoroutineScope.launch
    but the code after the
    launch
    block is still blocked by the
    launch
    block. What could I do to make this work?
    a
    • 2
    • 13
  • c

    Czar

    03/26/2020, 2:57 PM
    Hi, I have something like this:
    fun serviceSseRequest(sseEmitter: SseEmitter) {
      
      val liveOutput: Channel<String> = doSomethingInBackground()
      
      liveOutput.consumeAsFlow().collect { sseEmitter.emitServerSideEvent(it) }
    }
    How do I determine that there won't be any more messages in the channel? Maybe there is some other component that I can use instead of the channel here?
    a
    d
    b
    • 4
    • 7
  • o

    Orhan Tozan

    03/26/2020, 3:53 PM
    In the context of viewmodels/android, which one of the following three is recommended (in general for events from view => viewmodel)
    // option 1
    interface HomeViewModel {
        fun onLoginButtonClick()
    }
    
    // option 2
    interface HomeViewModel {
        val loginButtonClicks: SendChannel<ButtonClick>
        object ButtonClick
    }
    
    // option 3
    interface HomeViewModel {
        val loginButtonClicks: Flow<ButtonClick>
        object ButtonClick
    }
    z
    w
    d
    • 4
    • 118
  • d

    David Glasser

    03/26/2020, 5:51 PM
    ok i swear i knew the answer to this one but — if I want to run some Java function that blocks and might be slow and get a timeout from it, how do I do that? will this do the trick?
    withTimeout(5000L) {
      withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
        somePotentiallySlowThreadBlockingFunction()
      }
    }
    Note that I'm perfectly fine with the fact that the timeout won't actually stop the work from happening in
    somePotentiallySlowThreadBlockingFunction
    . This is happening at global process shutdown so the important thing is being able to move on to the next step of shutdown in finite time, not absolutely making sure that
    somePotentiallySlowThreadBlockingFunction
    doesn't continue. Like, I know
    withTimeout
    alone won't work with non-cooperative code, but does the withContext maybe make it work?
    • 1
    • 2
  • t

    Tmpod

    03/26/2020, 11:30 PM
    Hey! I did a quick search on this channel about asynchronous and coroutine safe subprocesses, and I didn't find anything relevant. Any suggestions on how to achieve this properly? (thinking of Python's
    asyncio.create_subprocess_shell
    )
    d
    c
    • 3
    • 5
  • j

    JP

    03/27/2020, 12:16 PM
    Is there a way to produce a UML class diagram from the coroutines library source code? Or has anyone produced it already? I thought it would be helpful to have it to learn better about coroutines, as a beginner.
    d
    • 2
    • 5
  • a

    Adam Grzybkowski

    03/27/2020, 12:25 PM
    Hi! I have a problem with testing the Flow using FlowAssert from SqlDelight library. It might be related to FlowAssert, but tbh I feel like I know nothing right now :D I created a repo with the problem here, you can find there two branches
    master
    and
    sqldelight
    On master branch I've tried to reproduce the original problem I've encountered when testing SqlDelight but without the SqlDelight code. The problem Tests are stuck when
    TestCoroutineDipsatcher
    is injected and used in
    flowOn
    operator here.
    fun getData(): Flow<Pair<String?, String?>> {
        val flow1 = channel1.asFlow()
            .flowOn(dispatcher)
        val flow2 = channel2.asFlow()
            .flowOn(dispatcher)
        return flow1.combine(flow2) { data1, data2 ->
                data1 to data2
            }
            .flowOn(dispatcher)
    }
    
    suspend fun addData1(value: String?) = withContext(dispatcher) {
        channel1.send(value)
    }
    
    @Test
    fun `receives data1`() = runBlocking {
        exampleDataSource.getData()
            .test {
                assertEquals(null to null, expectItem())
    
                exampleDataSource.addData1("data1")
                assertEquals("data1" to null, expectItem())
    
                cancel()
            }
    }
    So far I've been able to make the tests pass by removing the
    flowOn
    operator or by changing the injected dispatcher to
    Dispatchers.Unconfined
    Question Why is this happening? Could anyone explain me why using
    flowOn
    operator is causing this? I may be using this wrong coming from Rx word 😕 repository url https://github.com/AdamGrzybkowski/coroutineTestingProblem
    t
    w
    • 3
    • 3
  • m

    Michael de Kaste

    03/27/2020, 1:07 PM
    Anyone know any good parallel sequence library? I'd like the same functional equivalent of parallelstreams, but not in streams. (because switching between kotlin-style collection operators and stream operators are tedious and ugly)
    t
    • 2
    • 1
  • o

    Orhan Tozan

    03/28/2020, 4:27 PM
    I'm trying to define a
    val textField: Flow<String>
    that depends on a
    val textInputEvents: Channel<TextInputEvent>
    and a
    val clearTextFieldEvents: Channel<ClearTextInputEvent>
    . I'm trying to initialize the textField flow by combining the textInputEvents and clearTextFieldEvents channels and decide the value of the text field based of those two event streams, only problem is that just
    val textField: Flow<String> = textInputEvents
        .consumeAsFlow()
        .combine(clearTextFieldEvents.consumeAsFlow()) { textInputEvent, clearTextFieldEvent ->
            // Which one of the two just emitted?
            // return textInputEvent.text or ""
        }
    wouldn't do it, since I have to know which one of the channels emitted value is the most recent one, which isnt possible. So my question kinda is: is there a combine operator that also tells you which flow emitted the most recent value? EDIT: perhaps this is a usecase for the select expression (https://kotlinlang.org/docs/reference/coroutines/select-expression.html) ?
    d
    • 2
    • 6
  • e

    Erik

    03/28/2020, 8:30 PM
    Edit: questions 1 and 2 answered in thread, question 3 remains unanswered. --- I'm trying to broadcast values to multiple flow collectors. The goal is to have all collectors receive the same values. In this example, values -1, 0, 1 and 2 are sent over the channel. There are three collectors, so the goal is to have all three collectors receive the four values, for a total of 12 collect events. I tried using a
    Channel
    and
    bro.receiveAsFlow()
    , but that results in the fan-out principle where the four values sent are handled once by any of the available collectors, but not each by all collectors. The alternative is to use a
    BroadcastChannel
    and
    bro.asFlow()
    instead, but then the collectors receive... nothing! :\ 1. Why don't they receive any values? I.e. what am I doing wrong? 2. How can I make this work? As far as I understand
    BroadcastChannel
    can be used to send a value to multiple receivers. And the
    asFlow()
    extension on it should open a new subscription for every collector? Clearly I'm doing something wrong, but I don't see it. Bonus questions I don't know the answer of: 3. Is this possible at all with channels and flows? I found this open issue (https://github.com/Kotlin/kotlinx.coroutines/issues/1261) about a
    Flow.share
    operator, which obviously doesn't exist yet. Is this what I might be looking for?
    broadcast.kts
    d
    t
    +2
    • 5
    • 17
  • j

    jeggy

    03/29/2020, 4:02 PM
    When using
    runBlockingTest
    and my test fails with "This job has not completed yet" what are some ways of figuring out what is causing this? I like that it does fail, but it doesn't bring any information on where the problem is.
    g
    • 2
    • 8
  • m

    myanmarking

    03/29/2020, 6:56 PM
    hey guys. is there any ETA for the DataFlow api for flows ?
    t
    b
    • 3
    • 4
  • j

    Jakub Pi

    03/29/2020, 10:46 PM
    I have a
    Map<FileKey, Deferred<String>>
    where I want to cache (expensive-to-compute) SHA-512 results. My objective is to only calculate hash values once, on the first retrieval from the Map. So I know I want some kind of Future object. I know I can start the computation in the getter (unless it's already complete) and then just return the result normally. But is Deferred the best way to do this or is there a different construct/pattern I should be looking at instead? I probably want to block on the retrieval, so Deferred may not be the best choice.
    r
    • 2
    • 3
  • v

    vineethraj49

    03/30/2020, 6:30 AM
    is there a way to create a
    <http://Dispatchers.IO|Dispatchers.IO>
    "clone" which has an even lesser number of threads? I see that
    <http://Dispatchers.IO|Dispatchers.IO>
    is defined as
    LimitingDispatcher(this, parallelism, TaskMode.PROBABLY_BLOCKING)
    , should it be possible to re-use the same implementation?
    t
    • 2
    • 1
  • p

    Paul Woitaschek

    03/30/2020, 3:32 PM
    I'm trying to create my own version of combine because of https://github.com/Kotlin/kotlinx.coroutines/issues/1683 As the current combine implementation uses a lot of internal apis I can't just copy-past it. My code so far looks like this: https://gist.github.com/PaulWoitaschek/34225bfdea65e042431c6e57e72768f7 Can you review this and tells me if this a correct implementation?
    a
    • 2
    • 1
  • k

    kevinherron

    03/30/2020, 8:06 PM
    is there a version of
    Flow.debounce
    that has a “failsafe” timeout - so that in the face of continuously emitted events at a rate faster than the debounce timeout something is at least occasionally emitted
    t
    • 2
    • 5
  • s

    spierce7

    03/31/2020, 4:54 AM
    If I want to output a value from
    Flow
    if nothing else is output, and it completes, what’s the best way to do that?
    z
    a
    +2
    • 5
    • 7
  • j

    Jan Skrasek

    03/31/2020, 9:42 AM
    Hi, I need share operator. The implementations seem to be quite complicated so I've written this. Do you have any idea why it shouldn't work correctly?
    import kotlinx.coroutines.*
    import kotlinx.coroutines.channels.*
    import kotlinx.coroutines.flow.*
    import java.util.concurrent.atomic.*
    
    fun <T> Flow<T>.share(): Flow<T> {
      val channel = ConflatedBroadcastChannel<T>()
      val counter = AtomicInteger()
      var job: Job? = null
    
      return channel
        .asFlow()
        .onStart {
          if (counter.incrementAndGet() == 1) {
            job = GlobalScope.launch {
              this@share
                .catch {
                  channel.close(it)
                }
                .collect {
                  channel.offer(it)
                }
            }
          }
        }
        .onCompletion {
          if (counter.decrementAndGet() == 0) {
            job?.cancelAndJoin()
            job = null
          }
        }
    }
    e
    b
    • 3
    • 8
  • p

    Pacane

    03/31/2020, 12:26 PM
    Hi, I'm trying to transform a callback-based function to a coroutine. Here's what I have so far
    suspend fun fastSubscribe(path: String): Value =
                suspendCancellableCoroutine { cont: CancellableContinuation<Value> ->
                    val handler = object : Handler<SubscriptionValue> {
                        override fun handle(event: SubscriptionValue) {
                            requester.unsubscribe(path, this)
                            cont.resume(event.value)
                        }
                    }
    
                    requester.subscribe(path, handler)
                }
    Here I want to finish the execution with the value in the callback when I have one, but I'd like to add a timeout for if I never get a value (ie: when
    handle
    is never called) I think I should use a
    withTimeout
    in there but I don't know where exactly. On timeout I need to call
    requester.unsubscribe(handler)
    , so having the
    withTimeout
    on the call site of
    fastSubscribe
    isn't really a solution. Is there anything I can do with this?
    t
    s
    • 3
    • 5
  • a

    Antoine Gagnon

    03/31/2020, 7:06 PM
    I’m having some trouble on how to design something with coroutines: I want to do multiple tasks in parallel, but if one of them throws I want to stop all the other ones (putting them in the same coroutineScope seems to do that properly) but I also want to be able to catch any error thrown by the coroutine in the function that launched them (this part is the one I’m struggling with)
    s
    e
    • 3
    • 3
  • r

    rrva

    04/01/2020, 5:35 PM
    resilience4j ?
    s
    • 2
    • 1
  • m

    MartinZaubitzer

    04/01/2020, 8:35 PM
    Hey people, I have already asked this in the android channel, but this channel seems to be the better choice. I am struggling to combine coroutines and callbacks for my implementation: I am developing a BLE Server-Client communication protocol which includes messages that receive a custom answer from the peripheral. Now I would like to use coroutines and channels to make a queue of messages to send and only send the next message after a successful response from the peripheral. Currently I am not able to understand how I can await the result of the ble callback since it is not a function that returns anything. Thanks in advance!
    z
    l
    • 3
    • 6
  • a

    Andrey Stepankov

    04/02/2020, 1:57 PM
    Hi, can someone explain why exception is not consumed by try/catch? Steps to reproduce: fast clicks on button full project
    class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
      private val singleThread = this + newSingleThreadContext("SingleThread")
    
      override fun onCreate(savedInstanceState: Bundle?) {
        Timber.plant(Timber.DebugTree())
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
        val api = PokemonApi.createApi()
        button.setOnClickListener {
          singleThread.launch {
            try {
              val names = async { api.getPokemonNames() }
              val types = async { api.getPokemonTypes() }
              val stages = async { api.getPokemonStages() }
              val owners = async { api.getPokemonOwners() }
    
              names.join()
              types.join()
              stages.join()
              owners.join()
            } catch (e: UnknownHostException) {
              // exception is not consumed
            }
          }
        }
    
        val crashHandler = Thread.getDefaultUncaughtExceptionHandler()
        val exceptionHandler = Thread.UncaughtExceptionHandler { thread, exception ->
          try {
            Timber.tag("UncaughtException").e(exception)
          } finally {
            crashHandler?.uncaughtException(thread, exception)
          }
        }
        Thread.setDefaultUncaughtExceptionHandler(exceptionHandler)
      }
    
      interface PokemonApi {
        @GET("/names")
        suspend fun getPokemonNames()
    
        @GET("/types")
        suspend fun getPokemonTypes()
    
        @GET("/stages")
        suspend fun getPokemonStages()
    
        @GET("/owners")
        suspend fun getPokemonOwners()
    
        companion object {
          fun createApi(): PokemonApi {
            return Retrofit.Builder()
              .baseUrl("<https://unavailable-host.com>")
              .build()
              .create(PokemonApi::class.java)
          }
        }
      }
    }
    stacktrace
    E/UncaughtException: <http://java.net|java.net>.UnknownHostException: Unable to resolve host "<http://unavailable-host.com|unavailable-host.com>": No address associated with hostname
            at <http://java.net|java.net>.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:156)
            at <http://java.net|java.net>.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
            at <http://java.net|java.net>.InetAddress.getAllByName(InetAddress.java:1152)
            at okhttp3.Dns$Companion$DnsSystem.lookup(Dns.kt:49)
            at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.kt:164)
            at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.kt:129)
            at okhttp3.internal.connection.RouteSelector.next(RouteSelector.kt:71)
            at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:199)
            at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:108)
            at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:76)
            at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:245)
            at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
            at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
            at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
            at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
            at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
            at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
            at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
            at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
            at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:197)
            at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:502)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
            at java.lang.Thread.run(Thread.java:919)
        	Suppressed: <http://java.net|java.net>.UnknownHostException: Unable to resolve host "<http://unavailable-host.com|unavailable-host.com>": No address associated with hostname
        		... 24 more
        	Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
            at libcore.io.Linux.android_getaddrinfo(Native Method)
            at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
            at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:200)
            at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
            at <http://java.net|java.net>.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
            		... 23 more
         Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
            at libcore.io.Linux.android_getaddrinfo(Native Method)
            at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
            at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:200)
            at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
            at <http://java.net|java.net>.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
            	... 23 more
    E/AndroidRuntime: FATAL EXCEPTION: SingleThread
        Process: com.example.myapplication, PID: 24936
    s
    l
    • 3
    • 15
Powered by Linen
Title
a

Andrey Stepankov

04/02/2020, 1:57 PM
Hi, can someone explain why exception is not consumed by try/catch? Steps to reproduce: fast clicks on button full project
class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
  private val singleThread = this + newSingleThreadContext("SingleThread")

  override fun onCreate(savedInstanceState: Bundle?) {
    Timber.plant(Timber.DebugTree())

    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val api = PokemonApi.createApi()
    button.setOnClickListener {
      singleThread.launch {
        try {
          val names = async { api.getPokemonNames() }
          val types = async { api.getPokemonTypes() }
          val stages = async { api.getPokemonStages() }
          val owners = async { api.getPokemonOwners() }

          names.join()
          types.join()
          stages.join()
          owners.join()
        } catch (e: UnknownHostException) {
          // exception is not consumed
        }
      }
    }

    val crashHandler = Thread.getDefaultUncaughtExceptionHandler()
    val exceptionHandler = Thread.UncaughtExceptionHandler { thread, exception ->
      try {
        Timber.tag("UncaughtException").e(exception)
      } finally {
        crashHandler?.uncaughtException(thread, exception)
      }
    }
    Thread.setDefaultUncaughtExceptionHandler(exceptionHandler)
  }

  interface PokemonApi {
    @GET("/names")
    suspend fun getPokemonNames()

    @GET("/types")
    suspend fun getPokemonTypes()

    @GET("/stages")
    suspend fun getPokemonStages()

    @GET("/owners")
    suspend fun getPokemonOwners()

    companion object {
      fun createApi(): PokemonApi {
        return Retrofit.Builder()
          .baseUrl("<https://unavailable-host.com>")
          .build()
          .create(PokemonApi::class.java)
      }
    }
  }
}
stacktrace
E/UncaughtException: <http://java.net|java.net>.UnknownHostException: Unable to resolve host "<http://unavailable-host.com|unavailable-host.com>": No address associated with hostname
        at <http://java.net|java.net>.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:156)
        at <http://java.net|java.net>.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
        at <http://java.net|java.net>.InetAddress.getAllByName(InetAddress.java:1152)
        at okhttp3.Dns$Companion$DnsSystem.lookup(Dns.kt:49)
        at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.kt:164)
        at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.kt:129)
        at okhttp3.internal.connection.RouteSelector.next(RouteSelector.kt:71)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:199)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:108)
        at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:76)
        at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:245)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:197)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:502)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
    	Suppressed: <http://java.net|java.net>.UnknownHostException: Unable to resolve host "<http://unavailable-host.com|unavailable-host.com>": No address associated with hostname
    		... 24 more
    	Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
        at libcore.io.Linux.android_getaddrinfo(Native Method)
        at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
        at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:200)
        at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
        at <http://java.net|java.net>.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
        		... 23 more
     Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
        at libcore.io.Linux.android_getaddrinfo(Native Method)
        at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
        at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:200)
        at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
        at <http://java.net|java.net>.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
        	... 23 more
E/AndroidRuntime: FATAL EXCEPTION: SingleThread
    Process: com.example.myapplication, PID: 24936
s

streetsofboston

04/02/2020, 2:02 PM
Have you installed a CoroutineException handling in the top-most CoroutineScope? https://medium.com/the-kotlin-chronicle/coroutine-exceptions-3378f51a7d33
👎 1
a

Andrey Stepankov

04/02/2020, 2:03 PM
Handle do not help me. I think that crash in same reason with https://jakewharton.com/exceptions-and-proxies-and-coroutines-oh-my/
l

louiscad

04/02/2020, 2:03 PM
Yes I can explain: you need to wrap all your calls to
async
in a local
coroutineScope
, and put your
try
block around it. Without it, the
launch
gets the crash, cancels all children coroutines and crashes its parent scope.
s

streetsofboston

04/02/2020, 2:05 PM
But wouldn’t calling
await()
on async calls’
Deferred<T>
results be sufficient?
a

Andrey Stepankov

04/02/2020, 2:05 PM
Hm.. it works. One moment i need to check it on real project.
l

louiscad

04/02/2020, 2:10 PM
@streetsofboston You need to understand structured concurrency. A crashing child coroutine (i.e. unhandled exception that is not a
CancellationException
) will cancel its parent scope. So if you want to handle errors without crashing the parent scope, you need a middle scope (
coroutineScope { ... }
), and catch exceptions/throwables around it. The intent of the behavior is to cancel fast work in the same scope if one fails, to avoid pursuing unneeded work that cannot be used as a part already failed.
s

streetsofboston

04/02/2020, 2:12 PM
But installing a
SupervisorJob
MainActivity’s CoroutineScope in the should be sufficient to not cancel the MainActivity’s CoroutineScope after a failure happens. In my opinion, if
names
fails, you want the others (
types
,
stages
, etc) to be cancelled as well.
(And I do understand structure concurrency 🙂 )
a

Andrey Stepankov

04/02/2020, 2:13 PM
So... in case like that: I will get error on launch coroute?
launch {
  try {
    getCats()
  } catch() {
    // no-op
  }
}

// getCats will throw UnknownHostException
suspend fun callApi() = httpClient.getCats()
l

louiscad

04/02/2020, 2:15 PM
If it's an Activity, you should use
lifecycleScope
extension brought by AndroidX Lifecycle runtime KTX 2.2.0+ that already uses a
SupervisorJob
for the case where you use independant
async
where one can fail while letting the other still be useful on its own.
💯 1
a

Andrey Stepankov

04/02/2020, 2:17 PM
No its not an activity. its
MainScope() + newSingleThreadContext("SingleThread")
s

streetsofboston

04/02/2020, 2:17 PM
val names = async { api.getPokemonNames() }
          val types = async { api.getPokemonTypes() }
          val stages = async { api.getPokemonStages() }
          val owners = async { api.getPokemonOwners() }

          val listOfResults = listOf(names, types, stages, owners).awaitAll()
          ... or call `await()` on each one individually depending on your use-case...
Your MainActivity implements a CoroutineScope. But as Louis said, use the
lifecycleScope
instead. It is all set up correctly already (
lifecycleScope.launch { …. }
) 🙂
a

Andrey Stepankov

04/02/2020, 2:28 PM
Yeah. All you advice works well with example. Samething another is wrong on real project. Thx.
Oh.. 🤦 As result is it my bad. I forget to add try catch in another place. Place with flow and async works perfectly.
View count: 17