Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Launch not executing when called inside a coroutinescope

Tags:

I'm calling launch inside a coroutinescope but it does not execute. Snackbar action listener is executing but the launch block is not executing for some reason.

CoroutineScope(Dispatchers.Main).launch {
    val scope = this
    val mn = snackbarManager(R.id.root)
    Snackbar
        .make(mn.container, R.string.recpt_deleted, Snackbar.LENGTH_LONG)
        .setAction(R.string.undo) {
            scope.launch { // not executing
                Toast.makeText(requireContext(),"Committing",Toast.LENGTH_LONG).show()
                Log.d("COMMIT", "calling commit")
            }
        }
        .show()
}
like image 718
Prodigy Avatar asked Oct 18 '20 07:10

Prodigy


People also ask

Why Inject Dispatchers?

Inject Dispatchers Don't hardcode Dispatchers when creating new coroutines or calling withContext . This dependency injection pattern makes testing easier as you can replace those dispatchers in unit and instrumentation tests with a test dispatcher to make your tests more deterministic.

What is co routine scope?

CoroutineScopeDefines a scope for new coroutines. Every coroutine builder (like launch, async, etc.) is an extension on CoroutineScope and inherits its coroutineContext to automatically propagate all its elements and cancellation.

What is CoroutineDispatcher?

The coroutine context includes a coroutine dispatcher (see CoroutineDispatcher) that determines what thread or threads the corresponding coroutine uses for its execution. The coroutine dispatcher can confine coroutine execution to a specific thread, dispatch it to a thread pool, or let it run unconfined.

How to provide coroutine scope?

The easiest way to create a coroutine scope object is by using the CoroutineScope factory function 1. It creates a scope with provided context (and an additional Job for structured concurrency if no job is already part of the context).


1 Answers

The scope you are using in Snackbar action listener is not the same scope you use to call the first launch function. To tackle the problem you can make a reference to the main CoroutineScope:

val scope = CoroutineScope(Dispatchers.Main)
scope.launch {
    // ...
    // in action listener:
    scope.launch { /*...*/ }
}

Or use another CoroutineScope in Snackbar action listener, for example, lifecycleScope property:

lifecycleScope.launch {
    Toast.makeText(requireContext(),"Committing",Toast.LENGTH_LONG).show()
    Log.d("COMMIT", "calling commit")
}

But in my opinion your code is a little bit mess. I think you should reconsider your approach and don't use the CoroutineScope to show the Snackbar.

UPDATE:

When you initialize scope variable in the first coroutine val scope = this, this scope becomes COMPLETED when the outer coroutine is finished. When you launch inner coroutine in Snackbar action listener the scope already has COMPLETED state. We can't launch a coroutine using CoroutineScope with COMPLETED state.

like image 89
Sergey Avatar answered Sep 30 '22 13:09

Sergey