Having a Compose for desktop app where a UI-input ...
# android
m
Having a Compose for desktop app where a UI-input triggers the load of images from online resources. The loading is done in a coroutine. As long as the UI is triggering new loads, the not yet resolved loading shall be canceled, so that only the last call will be executed. Not sure if I got the coroutine cancellation stuff right, it works as expected, but is there a better way? Thanks for thoughts.
private val modelScope = CoroutineScope(SupervisorJob() + <http://Dispatchers.IO|Dispatchers.IO>)
fun loadImageBitmap(id: Int) {
if (currentId == id) {
return
}
currentId = id
modelScope.coroutineContext.cancelChildren().also { print(".") }
//cancel all requests before the current one - prints a dot each just for demonstrating
modelScope.launch { //Coroutine #1
delay(500) //simulate longer http request
println("\njob ${this.coroutineContext.job.hashCode()} gets Image $id")
currentImage = withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
URL("$baseUrl$id-1.jpg").openStream()
}
.buffered()
.use(::loadImageBitmap) // loads image
}
}
c
A better way is probably to get a reference to the
Job
of whatever’s running and cancel that, rather than checking and cancelling children of the
CoroutineScope
itself.
Copy code
private var currentJob: Job? = null
private val modelScope = CoroutineScope(SupervisorJob() + <http://Dispatchers.IO|Dispatchers.IO>)
fun loadImageBitmap(id: Int) {
    currentJob?.cancel()

    currentJob = modelScope.launch {
        // load the image
    }
}
👍 1
m
this works as well, thanks
e
let coroutines manage the job cancellation:
Copy code
val requests = MutableSharedFlow(onBufferOverflow = DROP_OLDEST)
val job = modelScope.launch {
    requests.collectLatest {
        // load the image
    }
}
fun startLoadingImage(request) {
    requests.tryEmit(request)
}
otherwise you have to ensure thread safety around your
job
manipulation somehow
m
@ephemient thanks for your answer, but I do not quite understand how this is should to work... can you maybe give more detail?
Copy code
val requests = MutableSharedFlow(onBufferOverflow = BufferOverflow.DROP_OLDEST)

val job = modelScope.launch {
    requests.collectLatest {
        delay(500) //simulate longer http request
        println("\njob ${this.coroutineContext.job.hashCode()} gets Image $id")
        currentImage = withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            URL("$baseUrl$id-1.jpg").openStream()
        }
            .buffered()
            .use(::loadImageBitmap) // lädt die Bitmap vom Stream
    }
}
fun startLoadingImage(request) {
    requests.tryEmit(request)
}
this is most definatly not what you mean, as it does not even compile, what should the request be? sorry, got to look up SharedFlow docs first, I guess 😉