Created
July 15, 2021 20:36
-
-
Save arberg/e8225e63faf04a4c4fc20f6a0aa92649 to your computer and use it in GitHub Desktop.
Kotlin Coroutine Callback for result/error/cancel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dk.bnr.androidbooking.managers.model.AppInternalSilentException | |
import kotlinx.coroutines.CoroutineScope | |
import kotlinx.coroutines.Dispatchers | |
import kotlinx.coroutines.channels.Channel | |
import kotlinx.coroutines.launch | |
interface OnResultCallback<T> { | |
fun onNext(value: T) | |
fun onError(throwable: Exception) | |
fun onCancel() | |
/** | |
* Waits for result, and returns it | |
*/ | |
suspend fun await(): T | |
} | |
class DefaultOnResultCallback<T> : OnResultCallback<T> { | |
// An alternative to this is using the callbackFlow. Though note that the callbackFlow can also deliver more values, but so can Channels. The callbackFlow is also implemented using channels. | |
// See also callbackFlow: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/callback-flow.html | |
// See https://developer.android.com/kotlin/flow#callback | |
sealed class Result<T> { | |
class Success<T>(val value: T) : Result<T>() | |
class Failure<T>(val throwable: Exception) : Result<T>() | |
class Cancelled<T> : Result<T>() | |
} | |
private val channel = Channel<Result<T>>(1) | |
// See also callbackFlow: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/callback-flow.html | |
// does not work with MutableSharedFlow, see callbackFlow above | |
override fun onNext(value: T) { | |
send(Result.Success(value)) | |
} | |
override fun onError(throwable: Exception) { | |
send(Result.Failure(throwable)) | |
} | |
override fun onCancel() { | |
send(Result.Cancelled()) | |
} | |
private fun send(result: Result<T>) { | |
CoroutineScope(Dispatchers.Main).launch { | |
channel.send(result) | |
} | |
} | |
override suspend fun await(): T { | |
val result = channel.receive() | |
return when (result) { | |
is Result.Success -> result.value | |
is Result.Failure -> throw result.throwable | |
is Result.Cancelled -> throw AppInternalSilentException("Cancelled") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can be used with