CoroutineScope(SupervisorJob()) vs Global Scope - android

What is the difference between these two?
I was following a tutorial, and the teacher said we need a scope that lives as long as the app lives, created the scope manually with SupervisorJob. Doesn't GlobalScope do the same thing?
I researched about this, but couldn't find a proper explanation. Thanks.

The difference between these two specific examples is that GlobalScope cannot be cancelled, but the other one can. When you call cancel() on a CoroutineScope created with the CoroutineScope() constructor function, all of its children coroutines get canceled.
GlobalScope will throw an IllegalStateException if you try to cancel() it, because it has no Job to be a parent of coroutines that it launches.
When you call CoroutineScope() without passing it a Job, it gets a generic Job automatically to be the parent of its coroutines. A generic parent Job like this will cancel all of its children coroutines if any of them fail. If you explicitly use SupervisorJob(), then if any of its children fail, they won't cause all their siblings to be canceled. This is a behavior that is similar to GlobalScope, since GlobalScope coroutines have no siblings that they could cause to be cancelled through a shared parent.
The reason GlobalScope is discouraged is that it has no supervisory capabilities. It should only be used for coroutines that should run for the entire lifetime of an app session. But if you're doing important work that should not be cancelled on Android, coroutines are not a good choice anyway because they aren't handling the cases where your app is in the background. In those cases you should be using a service or WorkManager instead. So, the actual legitimate use cases for GlobalScope, or any CoroutineScope that is never cancelled, are extremely rare.
I think the reason they added #DelicateCoroutinesApi is that so many people were misusing GlobalScope. (Probably because they unfortunately used it in the beginner documentation on how to use coroutines.) It is not correct to get around the warning by using CoroutineScope(SupervisorJob()) or CoroutineScope(Dispatchers.IO), etc. instead of GlobalScope, because all that does is mask the warning without changing the behavior other than creating a redundant CoroutineScope. If you have a legitimate use for GlobalScope, you should use #OptIn(DelicateCoroutinesApi::class) to dismiss the warning.

Related

Network call when exiting the screen - Android coroutines

I am trying to implement a UI in a fragment, where user can make all sorts of updates and I need send it over to backend when user EXITS the screen. (Batch update)
I am using MVVM pattern, where network calls are performed from viewmodel . Now, viewModelScope.launch won't work here, since as soon as user exits, the coroutine is canceled by onCleared().
For now, I added GlobalScope and it works but I have also come across this and this question
Are there any other alternatives to accomplish this with Coroutines?
Coroutines are mostly recommended for work that should start immediately and is scoped to the lifecycle of a Fragment, Activity, ViewModel or any other object with a lifecycle. Since the rest of the coroutine builders are tied to scopes, they wont accomplish what you are trying to do, since the user might leave your app at any given time.
A better approach would be using WorkManager with CoroutineWorker, which isn't tied to your UIs or App lifespan and still takes the advantages of working with Coroutines. With WorkManager, your work could be enqueued when the user leaves your designated screen and will be guaranteed to run once the constraints you specify are fulfilled (for example having internet connection). I recommend you to check Android's Guide to background processing if you are still making up your mind on which solution to use.

Concurrency in kotlin coroutine flow

I am new to this kotlin coroutine flow, am wondering that how could i achieve the concurrency inside the flow, Whereas according to the documentation it says launch,scope and withContext cannot be used inside the flow. without this How would i able to achieve the concurrency in kotlin flow
Can anyone help me with this?
You're probably looking for the channelFlow builder. You can start a coroutine inside of it and emit the result once it's done. Its documentation states...
Creates an instance of the cold Flow with elements that are sent to a
SendChannel provided to the builder’s block of code via ProducerScope.
It allows elements to be produced by code that is running in a
different context or concurrently.
You can check its official documentation and its usage here.

Coroutines limits?

I have some questions about Coroutines: Can I launch a large numbers of Coroutines, with heavy work, in parallel?
For example, I have a list of objects, and for each object I want to do some heavy work.
Can I do a for loop and launch a Coroutine for each object in one time?
How Coroutine can handle a large number of works in parallel?
If memory is too low, Coroutine will wait before launching another Coroutine?
It is better to limit Coroutines with a newFixedThreadPoolContext for example ?
Can I launch a large numbers of Coroutines, with heavy work, in
parallel?
Yes, you can. Coroutines are really lightweight. In fact a lot of coroutine examples show you can launch thousands of coroutines at a time.
Can I do a For loop and launch a Coroutine for each object in one time
?
Yes, you can. Although I do not know how efficient that would be.
How Coroutine can handle a large number of work in parallel ?
Coroutines have the notion of Dispatchers which allow you to configure threading.
If memory is too low, Coroutine will waits before launch another
Coroutine ?
Coroutines behave like lightweight Threads, so memory management is up to you. I am not aware of a built in mechanism that would prevent a coroutine from being launched if the system does not have enough memory. Again, coroutines are lightweight so if you cannot launch a coroutine, there is probably something wrong going on.
It is better to limit Coroutines with a newFixedThreadPoolContext for
example ?
By using newFixedThreadPoolContext, you are not really limiting the number of coroutines you can launch. You are just enforcing a limit on the ThreadPool that will be created to launch the coroutine. Also from the newFixedThreadPoolContext docs note that it will be replaced in the future.

How does a Coroutine Continuation internally work?

I have been working with coroutines for few weeks and sometimes its tough to understand the real working difference between thread concurrency and coroutine concurrency.
How suspend functions works internally ? How is continuation block helping in resuming the computation after suspension.
How is sequential computation of the line of code inside coroutine not blocking the thread ? and how is it better than thread concurrency ?
How suspend functions works internally?
Briefly, on the Java platform a suspend fun compiles into bytecode that is dramatically different from a plain function. It receives a hidden extra parameter (the continuation), creates its own continuation object, and the entire body of the function is implemented (approximately) as a big switch statement that allows the function to jump into the middle of the body when resuming.
When a suspend fun suspends, the underlying Java method actually returns. The return value is a special COROUTINE_SUSPENDED singleton object which the framework knows how to interpret. It is the responsibility of the suspend fun itself to save the continuation object where it will be accessible when the result of the function is ready.
The official documentation has a good in-depth description of these details.
How is continuation block helping in resuming the computation after suspension.
This is related to what I said above, that the suspend fun itself is responsible for ensuring it gets resumed later on. It must do that inside the block provided by the function suspendCoroutineOrReturn. User code doesn't call it directly, but the more high-level analogs suspendCoroutine and suspendCancellableCoroutine. These take over the concern of resuming the coroutine on the appropriate thread and the developer is responsible only for ensuring that continuation.resume() is called with the result when it becomes available. This typically happens in a callback you pass to an async call.
You can study this answer that tries to explain the suspend-resume mechanism in a self-contained example.
How is sequential computation of the line of code inside coroutine not blocking the thread?
Because it actually compiles into returning from the function and later on resuming by jumping into the middle of the function body.
and how is it better than thread concurrency?
Native threads are heavyweight resources that take time to create and destroy. Coroutines are much lighter-weight and consequently you can start many more of them, and more quickly.
The internal workings are explained in the original design document https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md which has a section on "Implementation Details".

Which one is better approach while performing multiple background tasks Kotlin Coroutines or ThreadPool?

I'm trying to implement start syncing process while app comes foreground.
I want to make multiple API call in the background thread, Which one will be better approach for this scenario Kotlin Coroutines or ThreadPool executor
I have tried with Kotlin Coroutines, but it seems like it try to execute all functions call in parallel which cause some Lag in APP initial times. is there a best approach to execute multiple functions in parallel
of course, Kotlin Coroutines, because coroutines aren't necessarily bound to any particular thread. A coroutine can start executing in one thread, suspend execution, and resume on a different thread. Coroutines aren't managed by the operating system. They're managed at the user space level by the Kotlin Runtime.
Kotlin Co-routines are the way to go.
Why? :
They are cheap.
Increases code readability.
Configuration setup is less (as compared to RxJava) for simple tasks.
try this
viewModelScope.launch{
val function1Async=async{ function1()}
val function2Async=async{function2()
function1Async.await()
function2Async.await()
}
If the alternative is to use ThreadPools, then you should use coroutines. They are built to make this easier. Also, you would save some memory since you would be sharing threads with other processes.
If what you need is a single thread that's continuously running in the background. Then maybe a thread is the way to go to ensure it's execution is not interrupted by a pending coroutine. Although an isolated single threaded dispatcher should solve this problem (if you have it).
You mentioned experiencing lag? Was this lag averted when you used a threadpool? If this is an issue, then fire the coroutines from another coroutine. :)

Categories

Resources