What is the reason behind viewModelScope defaulting to MainThread when most of the use cases are using as a background thread?
I still can't think of one example in my project that require using the main thread in ViewModel.
Also, is there a better/shorter way than writing as below?
viewModelScope.launch(Dispatchers.Default) {
// codes here
}
Couple of reasons:
ViewModel is probably the closest layer to the UI, which means a lot of logic here is involved in updating the UI => launching in any other thread will mean that you'll have to switch back to the Main for updating things
Using any other dispatcher implies, that one knows what kind of operations will happen in the VM (like IO operations or some computing maybe?)
In general I think it's a good practice, to not handle thread switching in your VM and handle on the layer, which essentially knows what kind of operation will be run.
For example if you have a VM -> Repository -> LocalSource (database operations) & RemoteSource (networking), then I'd do the switching to the IO thread in the Remote and Local sources.
Related
I have a couple questions on kotlin coroutines.
how many thread could get involved when working with coroutines?
if we use just Dispatchers.Main, would only one thread get involved(single threaded)? if we use Dispatchers.IO, would multiple thread possibly get involved (maximum of 64 threads)?
what will be the use case for using Dispatchers.Main? most articles that I have read say all UI related works should present in Dispatchers.Main and background related works(like reading/writing data from/to database, network requests) needs to present in Dispatchers.IO but I don't understand what UI related works present in Dispatchers.Main since UI related work don't really necessary need coroutines (with Dispatchers.Main)
we use susepnd fuction with coroutines for some works that could block the current thread. For example, read data from disk, network requests, or high tense computation etc. if these works are executed by suspend function, what/who is in charge when these functions are suspended? I think something has to be working on these suspend functions anyway. will that be background threads that is in charge of below?
reading/writing data from/to databse
waiting for network request
computing high tense computation
please point out if my wording or questions are incorrect.
Thank you in advance.
I think you answered yourself. Short answer is: Dispatchers.Main - single thread, Dispatchers.Default - number of cores, Dispatchers.IO - at most 64. You can read about it here. Full answer is a little more complicated as limits could be reconfigured, they may differ on different platforms (e.g. JavaScript is always single-threaded), Default partially shares threads with IO, etc. We can also create our own thread pools.
I'm not sure what do you mean. Coroutines are generally never necessary in order to do anything. But if we use coroutines inside UI application, then we should use Dispatchers.Main for UI-related stuff.
We should almost never use blocking code inside coroutines (one exception is Dispatchers.IO). If we do that, the coroutine won't suspend, but just block, possibly making other parts of our application unresponsive or degrading the performance.
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'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. :)
Hi I am reading about rxjava2 which is basically for async operations. I found it has an operator concept which AsyncTask in android does not.
How else is rxjava2 different than AsyncTask?
RxJava is not "basically for async operation". That is only one aspect of it.
RxJava allows you to compose operations on data, such that the output of one operation can be used as the input to the next. This operates similarly to streams implementations.
RxJava uses this composability to allow some operations to occur in a multi-threaded environment. It does this by providing well-defined semantics for the operators when working with multiple schedulers. RxJava can use asyncTask to perform some operations.
RxJava manages back pressure requirements for some applications by using Flowable chains, while Observable chains have no back pressure requirements. The former is appropriate where buffering is required or explicit acknowledgment of dropped information needs to be made.
RxJava has clear error and error handling semantics.
asyncTask just handles asynchronous tasks.
AsyncTask is Android’s default tool for developers needing to do some simple long-ish running work in the context of a UI screen without blocking the UI.
The main problem with AsyncTask is:
MULTIPLE WEB SERVICE CALLS:
To solve this in AsyncTask create an inner AsyncTask subclass in our Activity/Fragment, perform the network operation in the background, and take the result of that operation and update the UI in the main thread.
this approach has some issues and limitations:
Memory/context leaks are easily created is an inner class and thus holds an implicit reference to the outer class Also, what if we want to chain another long operation after the network call? We’d have to nest two AsyncTasks which can significantly reduce readability.
ERROR HANDLING
What happens if something goes wrong? Unfortunately, there’s no out-of-the-box solution for this.
And other problem like device rotation, back press handle etc.
To solved this all problem look at RxJava
Handle Error using RxJava is like this:
webService.doSomething(someData)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
result -> resultText.setText("It worked!"),
e -> handleError(e));
Second, In multiple web services call.
public Observable<List<Weather>> getWeatherForLargeUsCapitals() {
return cityDirectory.getUsCapitals()
.flatMap(cityList -> Observable.from(cityList))
.filter(city -> city.getPopulation() > 500,000)
.flatMap(city -> weatherService.getCurrentWeather(city)) //each runs in parallel
.toSortedList((cw1,cw2) -> cw1.getCityName().compare(cw2.getCityName()));
}
Hope this may help you!!
Quoting the Android developer guide found here here its says
Additionally, the Andoid UI toolkit is not thread-safe. So, you must
not manipulate your UI from a worker thread—you must do all
manipulation to your user interface from the UI thread
What does it mean that the widget's is not thread safe ? What causes the application to crash when we change the name of a Button off the UI Thread. I understand there is a event queue for the UI thread, but how does a separate thread cause issues with this queue ? I tried looking around, and everywhere it says you cannot do it, but no reason why ?
When the documentation says that the UI toolkit is not thread-safe, this means that the UI toolkit is written in such a way that it assumes that all access to UI objects is made from a single thread. By making this assumption, the implementers of the UI toolkit can make unsynchronized access to all the UI objects without fear of data corruption. This makes the UI toolkit easier to implement, easier to test, and improves the performance of the UI toolkit (because it does not need to lock objects before manipulating them).
The UI toolkit is designed to run ONLY on the main thread (otherwise known as the "UI thread"). If you now access UI components from another thread, you run the risk of corrupting the UI toolkit's objects. To ensure that you don't do that, the UI toolkit designers do 2 things:
They write in the documentation that you aren't supposed to access the UI toolkit from outside the main thread
Some (but not all) methods of the UI toolkit check to see if you are making access from outside of the main thread and throw exceptions in such conditions
However, this doesn't forcibly prevent you from accessing the UI toolkit from another thread. In fact, you can probably change the text on a button from another thread without any bad side-effects. That said, you still shouldn't do it. Because in some cases you will cause crashes, in some cases you will find that the changes you make to the UI just get overwritten or ignored, etc.
I hope this makes sense.