Mihai Potra
07/17/2023, 8:18 AMHandler
, and return a FutureTask
. (i.e. AccountManager.getAuthToken)
The gist of it is that these methods basically end up invoking something like this:
val handler = optionalHandler ?: Handler(context.getMainLooper()) // unless given, always use the main looper handler. Context is the main Activity context for example.
<http://handler.post|handler.post>{ callback(futuretask) }
Now, I want to wrap these with coroutines, so I ended up writing something like the below, which works fine:
suspend fun doMethod() = suspendCancellableCoroutine<Bundle?> { continuation->
callback= {result -> //do stuff with result }
invokeAndroidMethod(..., callback, /* Handler */ null)
}
But, because I'm not passing in a handler, the callback
always ends up running on the main thread (main looper)
How can I ensure that the callback
always runs in a different thread than main?
Any way I can get a Handler
out of some coroutine scope/context, to pass it to invokeAndroidMethod
? How about getting it for the current/parent coroutine?
Example: If I ever want to do launch(<http://Dispatchers.IO|Dispatchers.IO>) { doMethod() }
to basically ensure that callback
also runs in <http://Dispatchers.IO|Dispatchers.IO>
Robert Williams
07/17/2023, 9:52 AMcontinuation.resume
as fast as possible with whatever data you have at which point control will be switched back to the parent dispatcher (IO) and the fact that you were briefly on the main thread won't be a problemRobert Williams
07/17/2023, 9:53 AMRobert Williams
07/17/2023, 9:54 AMasCoroutineDispatcher
if you want to dispatch things back to that thread (not sure why you'd ever need this, but it is exactly how Dispatchers.Main is implemented)Robert Williams
07/17/2023, 9:59 AMMihai Potra
07/17/2023, 10:05 AMMihai Potra
07/17/2023, 10:06 AMMihai Potra
07/17/2023, 10:08 AMlaunch { refreshAccounts() }
and probably I should've used launch {<http://Dispatchers.IO|Dispatchers.IO>) { refreshAccounts() }
or some other dispatcher insteadMihai Potra
07/17/2023, 10:11 AM<http://Handler.post|Handler.post>
call. I suppose that if I want to completely avoid any main thread work, I could pass a null
callback and handle the future in a separate thread that does a blocking call?Mihai Potra
07/17/2023, 10:12 AMcallback
is run via the handler, once the future
settles, but invokeAndroidMethod
returns the future (in its unsettled state initially, and future.getResult()
is a blocking call that returns when the future settles)Mihai Potra
07/17/2023, 10:13 AMfuture = invokeAndroidMethod(..., /* callback */, null, /* handler */ null)
launch(someDispatcher) {
result = future.getResult()
// Work with result.
}
Mihai Potra
07/17/2023, 10:14 AMRobert Williams
07/17/2023, 10:17 AMMihai Potra
07/17/2023, 10:22 AMfuture.getResult()
being a blocking op would prevent the doMethod
coroutine from being suspended?Mihai Potra
07/17/2023, 10:23 AMRobert Williams
07/17/2023, 10:30 AMRobert Williams
07/17/2023, 10:31 AMMihai Potra
07/17/2023, 10:59 AMMihai Potra
07/17/2023, 11:00 AM