I develop apps for Android. I was wondering how many Kotlin Stateflows can I observe at one time? Every observe that I do is done on different CoroutineScope created by myself, dispatched by IO dispatcher or provided by lifecycle components of Android frameworks.
I have done various operations such as simple additions in infinite loop inside coroutines and using Android Studio profiler I have observed that launching a lot of coroutines that perform calculations causes high load on CPU.
Having in mind that Stateflow never completes, every collect on it is blocking and done on different CoroutineScope as examples and docs says, what is maximum amount of Stateflows that I can observe at one time without bothering that I will highly use CPU, create too many threads or just simply run out of device resources?
Subscriptions are still coroutines, and coroutines are cheap. There's definitely no universal bound we could tell you.
every collect on it is blocking
It suspends, it doesn't block. And you can always use takeWhile or the like to only collect from it until you can stop, or you can cancel the coroutine that's doing the collection (e.g. with withTimeout).
The main constraint on performance is that updating a MutableStateFlow takes time linear in the number of subscribers to that StateFlow, so if you update a StateFlow with a thousand subscribers, it'll take ~a thousand times longer than updating a MutableStateFlow with only a single subscriber.
Related
I am building a fragment in Android which displays some data kept on a server. As long as the user is on this fragment, I would like to poll the server every x seconds. Additionally, I would like to stop this procedure once the user navigates away from this fragment. Is the optimum solution to this problem to use coroutines or a thread? Thank you for any assistance!
Polling is never a good option as you will keep on wasting resources while the server might have no new data to supply. However, if you are still keen on doing that, you can use any of the choices, i.e. coroutines and thread. In thread, you'd have to manage its lifecycle yourself whereas in coroutine you don't have to worry about anything as CoroutineScope takes care of all that for you. One incentive of going with Coroutines would be the supply of operators you can use on your flows, map and switchMap for instance.
A better solution would be to make use of SNS or firebaseRemoteMessagingService that can notify your application client, upon which you can request the server.
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.
Reactive programming with RxJava helps create nice and concise code for business processes that include UI dialogs and long-running async tasks. However, Android UI has its peculiarities that can break the process. A simplified example:
public void onProcessWasInitiatedByUser() {
someCompletableSource.startAndWaitForSomeLongProcess()
.flatMap(showModalDialogAndWaitForAnswer())
.flatMap(startAndWaitForSomeOtherLongProcess())
.flatMap(showAnotherModalDialogAndWaitForAnswer())
.subscribe(() -> {
// finalize the process after the user has entered and confirmed all the required data
});
}
Note: subscribeOn() and observeOn() not included in the example for brevity. I know that mixed UI + background processes will require thread switching to avoid UI freezes and direct UI calls from background threads.
The questions:
Considering that startAndWaitForSomeProcess might last long enough for the device to go to sleep, there is a very high chance to get a java.lang.IllegalStateException if attempting to show a modal dialog. How to ensure that modal dialog is displayed when the user unlocks the device, but still to keep the modal dialog as part of this Rx flow?
In theory, I've heard it is recommended to use viewmodels to solve UI lifecycle issues but I'm not sure how it would help in this situation. Ok, I can store the data inside a viewmodel and later show the dialog when the device wakes up... but then how do I continue with the same Rx flow that was started in onProcessWasInitiatedByUser? I would prefer not to break the flow into separate pieces and scatter them around some other event handlers. What should I do inside showModalDialogAndWaitForAnswer function to make them safe for locked screen cases and still wait for the answer from the user?
Less important - I'm not sure if my example is the nicest way to organize this. Is there any rule of thumb, when things should go inside flatMap and when should be left for the final subscribe, or when subscribe should be left entirely empty; or when it's best to use some different RxJava function? How do experienced RxJava developers organize it to avoid ambiguities and possible caveats?
Great questions. Here my observations:
startAndWaitForSomeProcess is an operation that should be executed in the background and a separate context that, once finished, notify the client (View). In this case, what you need is probably a background task or a Service.
Rx helps you to orchestrate both synchronous and asynchronous processes in the same or different Scheduler contexts. I do not recommend using it for this requirement since it would imply an extended UI blocking time, and the operations life cycle would be unmanageable.
It is recommended that conversations with UI be made through the subscribed Observer, not through the operator's chain, as side effects may induce bugs. I've written a useful guide called "The Clean Way to Use Rx," and in Item 33: Negotiating with UI, it talks about it.
I hope that I have helped you.
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.
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. :)