Paul Woitaschek
09/14/2019, 7:16 AMAllan Wang
09/14/2019, 7:18 AMoctylFractal
09/14/2019, 7:18 AMasync { cont.resume() }
I suppose, but it doesn't return a value, so you probably want to use launch
& join
. Seems like an XY problem though.Paul Woitaschek
09/14/2019, 7:19 AMoctylFractal
09/14/2019, 7:24 AMJob
, which you can already join
on.
A better model for your case might be to use an actor
for each code, so that all permission requests are automatically processed sequentially. Then you don't have to wait for anything.Paul Woitaschek
09/14/2019, 7:26 AMsuspendCancellableCoroutine
gives me a continuation and that's exactly what I needelizarov
09/14/2019, 7:33 AMCompletableDeferred
whould be a much better fit. Use and store them instead of continuations, and you'll have no problem waiting for the same one multiple times.Paul Woitaschek
09/14/2019, 7:35 AMsuspend fun request(permission: String): PermissionResult
So I need to store what kind of permission I was requesting, right?elizarov
09/14/2019, 7:37 AMsuspend fun request(permission: String) =
mapPermissionToDeferred.getOrPut(permsision) {
requestPermission(permission)
}.await()
uspend fun request(permission: String) =
mapPermissionToDeferred.getOrPut(permsision) {
appScope.async { requestPermission(permission) }
}.await()
where:
mapPermissionToDeferred: MutableMap<String, Deferred<PermissionResult>>
suspend fun requestPermission: (permission: String): PermissionResult
CompletableDeferred
with the last approach -- just use async
with a proper application-level scope)Paul Woitaschek
09/14/2019, 7:41 AMoctylFractal
09/14/2019, 7:41 AMCompletableDeferred
is on the right track. Basically, since (If I'm interpreting your words correctly) you can only call requestPermissions
one at a time, you can store the requestCode
& a CompletableDeferred
, then in your suspend fun request
, if it's non-null, await
it first. Then set the request code, a new CompletableDeferred
, and call requestPermission
. Then await your new deferred. You might need to use a Mutex
here to ensure it's concurrently-safe, or box the requests in a data object and use actor
to automatically sequential-ize* it. In onRequestPermissionsResult
, you can check the code against the field, then complete the deferred. No Map needed.elizarov
09/14/2019, 7:43 AMsuspend fun request
from your main thread (you can wrap its body into withContext(Dispatchers.Main) { ... }
to be sure, you'll never get two concurrent requests to the same permission, since the first one will get stored in the map via getOrPut
Paul Woitaschek
09/14/2019, 7:43 AMoctylFractal
09/14/2019, 7:43 AMnull
out the field before setting the result. that's perfectly fine GC-wisePaul Woitaschek
09/14/2019, 7:44 AMto be sure, you'll never get two concurrent requests to the same permissionNo, I must be sure to never get two concurrent requests ever, unregarding of the permission type
elizarov
09/14/2019, 7:45 AMPaul Woitaschek
09/14/2019, 7:47 AMCompletableDeferred
?elizarov
09/14/2019, 7:48 AMsuspend fun requestPermission: (permission: String, result: CompletableDeferred<PermissionResult>): PermissionResult = permission.send(permission to PermissionResult)
where
permissionActor = actor<Pair<String, PermissionResult>> {
for ((permission, result) in channel) {
val permission = getIt(...)
result.complete(permission)
mapPermissionToDeferred.remove(permission)
// ^^ this way future requests will request it again
}
}
CancellableContinuation
with CompletableDeferred
and instead of resume
call complete
.suspendCancellableCoroutine<Unit> { cont -> ... }
you can do:
val d = CompletableDeferred<Unit> /// why unit?
...
d.await()
octylFractal
09/14/2019, 7:56 AMrequestPermissionsDeferred = null
in onRequestPermissionsResult
, if you wish to clean upPaul Woitaschek
09/14/2019, 8:04 AMactor.send
waits till the actor is empty? How do I get a result from it?octylFractal
09/14/2019, 8:05 AMCompletableDeferred
. have the actor complete itlouiscad
09/14/2019, 1:22 PM