Crash: Crossinline modifier with delay function call causes IllegalStateException on Android
See original GitHub issueHey guys!
I’ve encountered a weird crash caused when using the delay
function, inside a suspend
lambda, passed down to a launch
coroutine builder.
My use-case is as follows:
Inside my BaseViewModel
(business logic layer), I’ve got an execute
function as follows:
protected fun execute(crossinline action: suspend () -> Unit) {
launch(main) { action() }
}
I use it whenever I have some work to do, which involves coroutines. This way I can hide the launch
with the main
coroutineContext in the BaseViewModel
, while still using suspension…
A sample case of using this would be next:
execute {
val data = getData { getTopRatedGamesUseCase(page) }
...
}
Where the getData
is another base suspend
function, which does some work in the background and returns the data.
However, if I proceed with using delay
in the getData
function, I receive the following error:
java.lang.IllegalStateException: call to 'resume' before 'invoke' with coroutine
.
The delay is used for some form of custom retry logic. I’ve pinpointed this error to delay
at first, but then, out of curiosity, I’ve tried to postpone the work in retry blocks with Thread.sleep
, and the code worked.
Then I tried forcing the launch
call, ignoring the execute
function, and it worked as well.
Finally I’ve tried removing the crossinline modifier on the action
parameter of execute
, and the code worked.
I’m not 100% sure why this happens, I realise it’s wanted behaviour, when a parent Job
is finished, that a child return from a suspension function will result in an exception. However, not sure if I’m using coroutines in a bad way, the crossinline modifier is the true culprit (some internal bug), or the launch implementation has some un-handled case.
Thanks in advance!
Issue Analytics
- State:
- Created 5 years ago
- Reactions:2
- Comments:6 (4 by maintainers)
Top GitHub Comments
Hey!
This code is sufficient to produce the error:
Hopefully this clarifies things a bit.
I use the
execute
andgetData
functions from my base layer, so that I can simply abstract away the UI and CommonPool contexts, leaving the top implementation unaware of scheduling/threading.It’s usually a larger chain of functions, through different architecture layers, but the example is good enough. If I try to delay a coroutine, from inside another
suspend
function, which has been inlined into alaunch
block, the crash occurs.The stack trace, when running the top code is as follows:
I won’t be attaching a project, since I literally opened a new project here, and wrote the code from the first snippet.
Yeah I’m seeing something like this too for this code: