https://kotlinlang.org logo
Title
c

curioustechizen

03/22/2019, 12:45 PM
We're converting a callback-style API into a coroutine using
suspendCancellableCoroutine
. We're looking for ways to signal progress in addition to completion and error. Currently, we pass a channel as a parameter to the suspending function through which we signal progress (this is conceptually similar to having a callback for progress). Are there other options? Like using the continuation object to signal progress?
s

streetsofboston

03/22/2019, 12:47 PM
A
Continuation
can be continued only once. It is like an Rx Single or Maybe. For multiple (more than one) 'callbacks', using a Channel is your best bet.
👍 1
d

Dico

03/22/2019, 12:49 PM
For progress callbacks I think it is better to use a receiver with a
setProgress
function. You can wrap a conflated channel with it if you want, that would make sense.
Just much cleaner way imo.
It also allows you to make abstractions in the receiver type, that allow the suspend function to delegate a portion of the work (progress range) to another function, that also returns progress updates
interface ProgressCallback {
    fun setProgress(value: Double)
    fun delegateProgress(portion: Double): ProgressCallback
}

inline fun ProgressCallback.delegateWork(portion: Double, block: ProgressCallback.() -> Unit) = delegateProgress(portion).block()
c

curioustechizen

03/22/2019, 1:03 PM
Actually - this is an async API so the function is not really blocking.
suspend fun downloadSomething() = suspendCancelableCoroutine<Result> {continuation->
	val listener = object: Listener{
		override fun onDownload(result: Result) = continuation.resume(result)
		
		override fun onProgress(percent: Int) {
			//Signal download progress here
		}
		
		override fun onFailure(e: Exception) = continuation.resumeWithException(e)
	
	}
	api.addListener(listener)
	api.startDownload(thing)
	
	continuation.invokeOnCancellation {
		api.cancelDownload()
		api.removeListener(listener)
	}
}