Hey guys, I’m trying to await a result of a callba...
# coroutines
s
Hey guys, I’m trying to await a result of a callback from the Amazon LWA sdk but it’s a bit advanced and confusing for me. This is their method:
Copy code
AuthorizationManager.getToken(context, SCOPES, tokenListener)
I want to wait for it to get the result in the listener and then continue on with my code but I can’t figure out if it’s at all possible.
s
Copy code
suspend fun getAuthManagerToken(context: Context, scopes: Scopes) : Token = suspendCoroutine { cont ->
    AuthorizationManager.getToken(context, scopes) { token ->
        cont.resume(token)
    }
}
s
The listener can return either a token or an error, its type is
Listener<AuthorizeResult, AuthError>
s
Is
AuthError
a
Throwable
?
l
@Schadenfreude Then use
resumeWithException
when there's an error, and if there's no
Throwable
, use your own
s
@streetsofboston, yes it’s a throwable
s
Copy code
suspend fun getAuthManagerToken(context: Context, scopes: Scopes) : Token = suspendCoroutine { cont ->
    AuthorizationManager.getToken(context, scopes) { token, error ->
        if (error != null) resumeWithException(error)
        else cont.resume(token)
    }
}
(I assumed the type(-name)s in my example… I don’t know their exact form)
s
So thanks to @streetsofboston I managed to figure it out here’s the final solution:
Copy code
private suspend fun getAuthManagerToken(context: Context, scopes: Array<Scope>): AuthorizeResult =
        suspendCoroutine { cont ->
            AuthorizationManager.getToken(context, scopes, object : Listener<AuthorizeResult, AuthError> {
                override fun onError(authError: AuthError) {
                    cont.resumeWithException(authError)
                }

                override fun onSuccess(authResult: AuthorizeResult) {
                    cont.resume(authResult)
                }
            })
        }
s
@Schadenfreude @streetsofboston Is there any reason not to use suspendCancellableCoroutine and cancel getToken() when not needed anymore?
s
`suspendCancellableCoroutine`: In the code-sample of Daniel, the
getAuthManagerToken
has no reason to cancel the suspended coroutine itself. The outer-scope that calls
getAuthManagerToken
still can cancel the suspended fun. (
suspendCancellableCoroutine
will just provide a
cont
to the implementation of
getAuthManagerToken
that now has an additional
cancel
function.)
s
Okay, if getToken() returns a cancellable call, then it makes sense to use suspendCancellableCoroutine
that way the pending getToken() request and its resources can be dropped early
s
If a cancelation happens, most of the time the outer-scope that calls the function does the cancelation. The
getAuthManager
doesn’t need to worry about it in this case. If the
getAuthManagerToken
itself needs to cancel it, then it needs to call
suspendCancellableCoroutine
so that it has a
CancelableContinuation
(not sure if I have the class-name right) instead of a plain
Continuation
and now it can call
cancel()
on it, if necessary, instead of calling
resumeWithException(...)
. Cancelation is almost(!!) like
resumeWithException
, because it cancels the suspending call, but it is not ‘fatal’, it has just canceled.
p
@louiscad I thought resumeWithExceptions was only for crashing cases, not for control flow
l
@pakoito It's to forward `Throwable`s back into the control flow from error/exceptions callbacks