has anyone else had trouble with using a channel i...
# coroutines
w
has anyone else had trouble with using a channel in a multiplatform context? right now i'm testing on android but for some reason my iterator over my channel is not receiving any values. when i attempt to reduce the problem and run it in a jvm only project it works fine though
Copy code
class PersistentWsClient() {
	private val scope = CoroutineScope(Dispatchers.Default)
    private val sendingQueue = Channel<Frame>(UNLIMITED)

    fun open(host: String, path: String, port: Int = 8080) {
        scope.launch {
            this@PersistentWsClient.e("waiting for messages")
            for (msg in sendingQueue) {
                this@PersistentWsClient.e(msg.toString())
            }
        }
    }

    fun send(payload: Frame) {
        scope.launch {
            for (i in 0..10) {
                delay(500)
                sendingQueue.offer(payload)
                this.e("offering $payload")
            }
        }
        sendingQueue.offer(payload)
    }
}
(i have stripped away some extra code). In this example i only ever get
Copy code
waiting for messages
offering <payload>
offering <payload>
...
i originally had the dispatcher use an expect /actual to get Dispatchers.IO too.
t
Maybe add either an
invokeOnCompletion
listener to the receiving
launch
or a log message after the iteration to make sure it's still receiving from the chanel?
Perhaps also confirm that your
offer
calls are returning
true
.
w
the completion body is not getting executed and
offer
is returning
true
. hmmm
@travis one thing i have noticed if they are in the same
scope.launch
it does seem to work (???)
Copy code
fun send(payload: Frame) {
        scope.launch {
            launch {
                for (i in 0..10) {
                    delay(500)
                    this@PersistentWsClient.e("offering? ${sendingQueue.offer(payload)} for $payload")
                }
            }

            launch {
                for (frame in sendingQueue) {
                    this@PersistentWsClient.e(frame.toString())
                }
            }
        }
    }
t
Must be something else going on in your codebase. Works for me as:
Copy code
class MainActivity : AppCompatActivity() {

    private lateinit var ws: PersistentWsClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ws = PersistentWsClient()
        ws.open("localhost", "/")

        setContentView(R.layout.activity_main)
        val button: Button = findViewById(R.id.test)
        button.setOnClickListener {
            (0..10).forEach { ws.send(Frame(it)) }
        }
    }
}

data class Frame(val value: Int)

class PersistentWsClient {
    private val scope = CoroutineScope(Dispatchers.Default)
    private val sendingQueue = Channel<Frame>(UNLIMITED)
    fun open(host: String, path: String, port: Int = 8080) {
        scope.launch {
            e("waiting for messages")
            for (msg in sendingQueue) {
                e(msg.toString())
            }
        }
    }
    fun send(payload: Frame) {
        scope.launch {
            for (i in 0..10) {
                delay(500)
                sendingQueue.offer(payload)
                e("offering $payload")
            }
        }
//        sendingQueue.offer(payload)
    }

    private fun e(msg: String) { println(msg) }
}
Copy code
2020-10-23 09:42:24.965 12926-13073/com.example.myapplication I/System.out: offering Frame(value=1)
2020-10-23 09:42:24.965 12926-13073/com.example.myapplication I/System.out: Frame(value=1)
2020-10-23 09:42:24.966 12926-13073/com.example.myapplication I/System.out: offering Frame(value=8)
2020-10-23 09:42:24.966 12926-13073/com.example.myapplication I/System.out: Frame(value=8)
2020-10-23 09:42:24.967 12926-13073/com.example.myapplication I/System.out: offering Frame(value=9)
2020-10-23 09:42:24.967 12926-13073/com.example.myapplication I/System.out: Frame(value=9)
2020-10-23 09:42:24.967 12926-13073/com.example.myapplication I/System.out: offering Frame(value=10)
2020-10-23 09:42:24.968 12926-13073/com.example.myapplication I/System.out: Frame(value=10)
2020-10-23 09:42:24.970 12926-13072/com.example.myapplication I/System.out: offering Frame(value=0)
2020-10-23 09:42:24.970 12926-13072/com.example.myapplication I/System.out: Frame(value=0)
2020-10-23 09:42:24.970 12926-13068/com.example.myapplication I/System.out: offering Frame(value=4)
2020-10-23 09:42:24.970 12926-12960/com.example.myapplication I/System.out: offering Frame(value=6)
...
w
@travis i agree, that's why i was wondering if multiplatform had anything to do with it because i wasn't able to reproduce elsewhere either 😕
t
Oh, sorry, I did not test in a multiplatform project. I am working on some multiplatform projects that use `Channel`s in Android, but haven't gotten to the point of testing them yet; so can't confirm/deny their proper operation yet.
Do you have the full project available (on, for example, a GitHub repo) to see if there are any other obvious configurations issues?
w
i don't currently have it up yet but heres probably the relevant config @travis in multiplatform :
Copy code
val commonMain by getting {
    dependencies {
        implementation("org.jetbrains.kotlin:kotlin-stdlib-common")

        implementation(Versions.Libs.COROUTINES_CORE)

...

        const val COROUTINES_CORE = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
in my android module i have
Copy code
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
i'll have to try and reduce it to an isolated example and publish that / make a bug report if it is still an issue
👍 1
t
i'll have to try and reduce it to an isolated example and publish that / make a bug report if it is still an issue
Ya, I think this would be the best option for getting further help and/or reporting a potential bug.
w
well after slamming my head on it i figured out i was creating multiple instances of that class (i forget to setup dagger to provide that as a singleton 🤦‍♂️ )
t
Yay! Glad you figured it out. :)