Handling loading states of multiple threads in Activity - java

In my Android app i'd like the user to be able to see when a task is running in the background.
These tasks can be either network calls or database operations, running on separate background threads.
There is a single indeterminate ProgressBar in the Activity, which i would like to show if any background tasks are running, and hide it otherwise.
I've searched for solutions to this and people seem to use LiveData for similar purposes.
So i figured i'd create a LiveData in the ViewModel of the Activity that represents the current loading state of the app, something like this:
val loadingState = MutableLiveData<State>()
Whenever i'm starting or finishing a task, i'd post the appropriate value to this LiveData:
// starting background operation
loadingState.postValue(Status.LOADING)
And i'd observe on it from the Activity and show/hide the ProgressBar according to the current state:
loadingState.observe(this, Observer { status ->
when (status) {
Status.LOADING -> showProgressBar()
Status.IDLE -> hideProgressBar()
}
}
My problem is i don't know how to handle this when there are multiple tasks running on multiple threads.
For example:
A task starts and sets the status to LOADING (correct)
B task starts (the status is already LOADING so nothing happens) (correct)
A task finishes and sets the status to IDLE, however B is still running (wrong)
The ProgressBar will be hidden even though B is still in progress
B task finishes, but the status is already IDLE (wrong)
I thought i could maintain a Collection of LiveData objects (as in a separate LiveData for each task) but it seems really cumbersome.
Is there an idiomatic way to handle this?
(Java answers are welcome as well)

i have a simple idea
in the view model use variable like that
var numberOFThreads = 0
and replace this line
loadingState.postValue(Status.LOADING)
with
if(numberOFThreads == 0){
loadingState.postValue(Status.LOADING)
}else{
numberOFThreads++
}
and
if(numberOFThreads == 0){
loadingState.postValue(Status.IDLE )
}else{
numberOFThreads--
}

Related

Is it possible for this Android LiveData/Threading code to give some kind of concurrency issue or unexpected result?

I have some similar code throughout my project that is inside of my ViewModels which subscribes to an RxJava observable that is subscribedOn Schedulers.computation(). I have a MutableLiveData<Integer> isLoadedLiveData object that posts an updated int flag that will be observed in my activity.
Basically, in this ViewModel, if 3 subscriptions finish, then the isLoadedLiveData will be equal to 3 because each subscriptions adds to increments the int flag value of isLoadedLiveData. And in my LiveData observer of isLoadedLiveData in my activity, I then set up the views of that Activity once the int value is equal 3. So it lets me know that the ViewModel data is ready to go and each needed piece of data can be returned from each repsective getter. I do this so I don't need a bunch of LiveData objects in my Activity and can instead just have one flag that tells me when all my separate data is loaded.
Here is a section of the code in my ViewModel:
Disposable disposable1 = this.thingRepository.getThingSingle()
.observeOn(Schedulers.computation())
.subscribe(thing -> {
name = thing.getName();
abbrev = thing.getAbbrev();
stuff = thing.getStuff();
loaded++;
isLoadedLiveData.postValue(loaded);
});
Now I'll preface this by saying I am not well versed in java/android concurrency, so I am not exactly sure, but I wouldn't think this code could give me some kind of problem. But I am not 100% sure. Could this possibly be problematic in certain situations, or will the sequence of code and threading not be an issue?
The data like name, abbrev, and stuff which are fields of my ViewModel are all returned to my Activity eventually (just through simple getters, no observers). Will these pieces of data always be correctly updated and safe to access from my Activity on the MainThread because the int flag being posted to isLoadedLiveData always occurs after the data is updated on the background threads. I am not completely sure because these values are being updated on a background thread and then the main thread accesses it. I don't know enough about concurrency.
This doesn't have much to do with RxJava but that is how I handle my threading in this case. It is more to do with Java Threading/Android Threading/LiveData in general. I am not completely sure how LiveData .postValue works, but I would assume it gets put in the main thread's Looper to execute my LiveData Observer callback with the posted value passed in. Will this no matter what always occur so that the values set above the isLoadedLiveData.postValue(loaded) are safe to access and correctly updated?
I appreciate any responses! Thanks.
Edit: Here is new code:
Disposable disposable1 = this.thingRepository.getThingSingle()
.subscribeOn(Schedulers.computation())
.doOnSuccess(thing -> {
name = thing.getName();
abbrev = thing.getAbbrev();
heavyOperationResult = heavyOpperation(thing);
stuff = thing.getStuff();
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(thing -> {
loaded++;
isLoadedLiveData.setValue(loaded);
});
I added .subscribeOn(Schedulers.computation()) even though my repository returns a Single that is already subscribed on Schedulers.computation() just to express what thread it was subscribed on for the purposes of this example. I also added the heavyOperation(thing) just to show that I need it in the background because I do some computation that could take too long for the main UI thread.
I disagree with that code snippet, you are mis-using Rx in my opinion.
Two things:
doOnSuccess is meant to be used for side-effects, not for doing heavy computations.
Do NOT take the state out of the Rx stream, pass it downstream instead. This statement name = thing.getName(); and others like that inside doOnSuccess are really dangerous because you could have several streams modifying the same state in different threads.
What you want is to actually pass the state downstream and eventually publish it in LiveData, then you observe it as it changes.
Disposable disposable = thingRepository.getThingSingle()
.subscribeOn(Schedulers.io())
.flatMap(thing ->
Single.fromCallable(() -> heavyOperation(thing))
.map(heavyOperationResult -> new Pair<>(thing, heavyOperationResult))
.subscribeOn(Schedulers.computation()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(pair -> {
Thing thing = pair.getValue0();
HeavyOperationResult heavyOperationResult = pair.getValue1();
thingLiveData.setValue(thing);
heavyOperationLiveData.setValue(heavyOperationResult);
});

Update TextView without Freezing Application

I'm reading Sensor Data from Device Sensors(Multiple Sensors) and call a Method to show the data I received from sensors to the designed TextView.
The method I'm calling to update TextView:
private void UpdateDataStream(String _Entry,Boolean isAppend)
{
if(isAppend)
ViewHolder.append("\n("+sensorName+")"+_Entry);
else
ViewHolder.setText("("+sensorName+")"+_Entry);
}
Method called from SensorEventListener's , onSensorChanged Event.
What I couldn't figure out is how to prevent freeze while updating TextView; since sensor data update is intensive(considering it is from multiple sensors simultaneously) updating TextView cause Application to freeze or crash. I don't need to "print" every data I received, like It is enough for me to print for every 1-2 second, lost data can be ignored.
Is there any approach/patern or built-in structure to achieve this ?
(I'm new to programming in Java&Android, yet I'm familiar with multiprogramming, parallel programming concepts, yet I couldn't figure out how to apply them in this environment)
This is fastest solution:
https://github.com/ReactiveX/RxJava
http://reactivex.io/documentation/operators/debounce.html
Or you can:
create stack (for example)
write sensors data stream to stack from thread#1
in another infinite loop thread#2 read last data from stack every N time (don't forget to synchronize them)
clean the stack
write last data to TextView (don't forget to set text in ui thread: textView.post( () -> textView.setText("safe call") );

How to create a thread that listens for a state change?

I was spending my entire morning figuring out how Android threads and locks work. I have read about Thread, Runnable, Handler, AsyncTask, Executors, HandlerThread, ThreadPoolExecutor, and so on. I have also read about Condition, Lock and the method synchronize. But, I am still hesitant about what type of thread should I use in my application.
Summarizing and simplifying, my app should do the following:
A working thread will be attached to a specific Fragment, which displays a GridLayout with different elements. That thread should generate random numbers that corresponds with each one of the grid elements and send them sequentially to the parent Fragment, which will hide them a fixed number of milliseconds. However, the thread should be able to pause itself when user clicks a button in the Fragment (requiring a kind of synchronized usage).
The questions are the following:
What kind of Android thread is the most optimal in my case?
What is the best way to listen for a change in the state inside the thread loop if a user want to pause it?
For now, I am considering to extend the raw Thread class and use synchronize() to check the state, but I feel that it is not the most appropiate way to achieve this.
Thanks in advance.
I think RxJava would be a good fit for this problem. I'm away from my IDE, but I envisage something where you:
Create a "Timer", with a random interval, for each individual item (say a GridItemViewModel) in your grid layout, and have it emit that item when it finishes.
Combine all those timers into a List.
Run all the timers simultaneously.
When each individual timer finishes, it emits its "item" (i.e. ViewModel). Use that to hide the appropriate item in your UI
When all items finish, it will trigger onComplete() in your overall Observable. When this is called, you know all tasks have fininshed.
So...
final List<Observable<Item>> tasks = gridItems()
.stream()
.map(item -> {
final int seconds = ThreadLocalRandom.current().next(0, 5);
return Observable.timer(seconds, TimeUnits.SECONDS).map(ignore -> item);
})
.collect(Collectors.toList());
Observable.merge(tasks)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(item -> {
//One item has completed. Take the "item" value
// and use it to update your UI.
}, t -> { /*No error handling*/}, () -> /*All items finished*/);

Waiting for threadpool to complete execution

I am new to threading . I have searched many questions related to my problem but I am not able to find the right solution for me. What I am doing is I am using four async tasks to fetch data from four different social media using the THREAD_POOL_EXECUTOR.
code is as follows.
new Fb().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new Twitter().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
...
mAdapter = new MyAdapter(getActivity(),
(ArrayList<Model>) showList);
mListView.setAdapter(mAdapter);
I want the calls to be in parallel to save the time of fetching data. Now the idea is that i want all the four threads to complete the work and after that I want to display the sorted data as per timestamp. Right now the problem is that my setAdapter get called before the four threads complete fetching data as adapter is set on the UI thread. I want a mechanism to block the UI thread until all four threads complete fetching the data.
I have found that maybe I can use the shutDown() and awaitTermination() methods of ExecutorService . It would be great if anyone can help me in anyway. Thanks a lot
What I would do is:
Create an empty ArrayList in your activity
Pass this arrayList to your adapter and set the adapter on your ListView. setAdapter method will not affect the listView - it will still be empty becase the list is empty.
Start 4 AsyncTasks and fetch data. In onPostExecute() add this data to the ArrayList and invoke notifyDatasetChanged() on the adapter.
You should never block an UI thread because it is just wrong. When you want all data to be shown at once you can make a simple counter, make counter++ in every onPostExecute and invoke notifyDatasetChange() only when counter is 4.
Invoke method shutdown() from ExecutorService.
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html
If you're really okay with blocking the UI thread, try this:
new Fb().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new Twitter().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
...
AsyncTask.THREAD_POOL_EXECUTOR.shutdown();
while (!AsyncTask.THREAD_POOL_EXECUTOR.isTerminated()) {}
mAdapter = new MyAdapter(getActivity(),
(ArrayList<Model>) showList);
mListView.setAdapter(mAdapter);
In most cases though, blocking the UI thread isn't a good idea.
I could successfully handle the problem without going deeo into threading. I used the simple concept of making booleans true after execution of each thread. And in the UI thread I checked for infinte time i.e
while(true)
{
if(flag1 && flag2 && flag3 && flag4)
{
//set the adapter and make the flags false
break;
}
}
Dont forget to make the falgs false otherwise execution will go on for indefinite time.

Howto to associate a progressdialog with a service in Android

I have a sync service using AsyncTask. Due to its objective (sync), I prefer to block the user and show him a progressdialog. (And error if exists)
Another difficulty is that I have about 8 AsyncTask running simultaneously. So I can't do a simple call to the progress dialog page when I begin the work and a close when it's finished. It's more complex.
Can someone help me with that task ?
Regards
onPreExecute(), onProgressUpdate(Progress...) and onPostExecute(Result) in AsyncTask are invoked on the UI thread. You can use these to display a progress bar, update it as the syncing progresses and hiding it when the work is finished.
As to the 8 simultaneous async tasks, do you really need 8 concurrent tasks? Can't you run them sequentially on one background thread using a single AsyncTask?
In the first place the point of the Service is that you don't need/want to block user to do stuff because it happens in the background. To that aspect, a Service doesn't have a UI thread, so if you want a progress bar shown in your Activity you'll have to send an Intent back to your activity (using broadcast receivers), such that you can switch the progress bar on/off and do other magic.
I would not recommend blocking the user though, because the tasks you are doing might take a very long time, giving a nasty user experience. You might even want to reconsider using a Service at all (if the data you are fetching is only used locally; for example fetch the latest twitter messages or something) and just go with an ASyncTask in your Activity, unless the data your Service fetches is used in other parts of your app as well (widgets for example) and you want that data available even if the activity isn't running.
You can make use of progress dialog to show wait cursor kinda thing.
Also you can imitate the concept of CountDownLatch in your application to dismiss the cursor. Like you can have a static function in a class like updateTaskComplete and update a static counter. And once the counter is equal to number of async task then in the function updateTaskComplete cancel the progress cursor. I mean you have to do something on this line.

Categories

Resources