Reputation: 95
I've searched everywhere and I haven't found anything that seems to be a solution to my problem
I have a function using coroutines:
fun onAuthenticated() {
launch (Dispatchers.IO) {
userRepo.retrieveSelf()!!.let { name ->
userRepo.addAuthenticatedAccount(name)
userRepo.setCurrentAccount(name)
}
activity?.setResult(Activity.RESULT_OK, Intent())
// this block doesn't seem to be run
withContext(Dispatchers.Main) {
Log.d(TAG, "ok looks gucci")
activity?.finish()
}
}
}
When this function is called, the code in the withContext(Dispatchers.Main) { ... }
block doesn't run. I'm using it to access the activity in the main thread.
I've been getting kind of frustrated and I'm not sure if I don't understand how the dispatcher/coroutine is supposed to work or there's something I'm missing.
Let me know if you need any additional details or code!
EDIT
So Marko was right. After I moved the activity.?.setResult(Activity.RESULT_OK, Intent())
so that it was being run with the main dispatcher, I found out there was another part of the code in userRepo.setCurrentAccount(name)
that was giving an issue. After updating the code as seen below, it works as expected!
override fun onAuthenticated() {
val handler = CoroutineExceptionHandler { _, e ->
Snackbar.make(
web_auth_rootview,
"Authentication unsuccessful",
Snackbar.LENGTH_INDEFINITE
).show()
}
launch(Dispatchers.Main + handler) {
userRepo.retrieveSelf()!!.let { name ->
userRepo.addAuthenticatedAccount(name)
userRepo.setCurrentAccount(name)
}
activity?.apply {
setResult(Activity.RESULT_OK, Intent())
onBackPressed()
}
}
}
Big Thanks to Marko for helping me out!
Upvotes: 4
Views: 2228
Reputation: 200296
activity?.setResult(Activity.RESULT_OK, Intent())
Here you try to touch a GUI component from the IO thread. This probably throws an exception, but since it's on the IO thread, nothing catches it.
You can wrap everything in a try-catch, but your program would automatically work better if you used the proper idiom, which is to launch
in the Main
dispatcher and only switch to the IO context for the blocking operations:
launch(Dispatchers.Main) {
withContext(Dispatchers.IO) {
userRepo.retrieveSelf()!!.let { name ->
userRepo.addAuthenticatedAccount(name)
userRepo.setCurrentAccount(name)
}
}
activity?.setResult(Activity.RESULT_OK, Intent())
Log.d(TAG, "ok looks gucci")
activity?.finish()
}
Now, if you get an exception in the IO dispatcher, it will propagate to the top-level coroutine, which will cause an exception on the main thread, and your application will crash with it. This is a solid foundation to add your error handling logic on top of.
Of course, this is still not the way you should work with coroutines because you're missing the structured concurrency aspect.
Upvotes: 3