I need some work to be done on the UI thread, but this means I can't also (that I know of) display a ProgressBar as the UI is busy executing other tasks.
I know this sounds a bit illogical, but is there a way to display an indefinite ProgressBar on the UI thread while the UI thread is busy?
I am aware of using Runnables and AsyncTasks, I'd use them to complete the actual work if I could, but can these be used for displaying the ProgressBar itself?
Just show a textview with Loading... in it, or some other static view (imageview with progress, that doesnt spin). Any other solution will need to do the work on the UI.
I would really check my code in order to free the UI because the if u use the UI for too long the user wouldnt be able to press back or anything and he will feel as the the app is stuck.
The short answer is no.
If your UI thread block due to heavy work, the UI does not get updated.
But I am sure you can improve you code so that it does not block the UI thread.
Yes, you can display an indefinite ProgressBar on the UI thread with the help of AsyncTask.
onPreExecute() {
// Display Progressbar here
}
doInBackground() {
// Do some heavy task here, but not related to UI thread
}
onPostExecute() {
// Dismiss the Progressbar
}
Related
I tried to use ProgressBar in my Activity when I execute a short-time operation. And I realized that when I set ProgressBar visibility to true, It becomes visible only after the operation was executed.
progressBar.setVisibility(View.VISIBLE);
calculate();
Then I found the solution that I have to set ProgressBar visibility in another Thread. So my question is: why do I have to set it in another Thread?
For example, if I leave my ProgressBar with true visibility on creation (in onCreate()), it will progress and I can interact with UI in that moment. I concluded that they execute in one thread and It's okay. But It seems to me I'm wrong.
The Android UI toolkit is not thread-safe. This means that you must not manipulate your UI from a worker/background thread. you must do all manipulation to your user interface from the UI (Main) thread.
Android UI toolkit include elements in android.widget & android.view packages
Rule of Thumb:
Do not block the UI thread (don't run operations that have unspecified time in UI thread)
Do not access the Android UI toolkit from outside the UI thread
This is explained in more details in here
Running background threads using AsyncTask or Loaders always allow you to update your UI upon the background thread results in their onPostExecute() and onLoadFinished() respectively.
So, as of your question, you have to update your ProgressBar from the UI thread not from other threads.
my AsyncTask should wait till event in the UI-thread happen.
so, I started to have simple while loop. However, in some of the devices that caused the UI thread to freeze. so after reading the following answer:
Fatal Spin-On-Suspend/Stuck on ThreadID
[However, it is not quite the same - i put the while in the async-task not in main-activity]
I added Thread.sleep - and it seem to indeed solve the problem.
However, I feel like I'm doing something wrong here...I wonder what is the right way to do it.
Do not ever sleep or block the UI thread. Wait in the background thread of the AsyncTask.
One way is as suitianshi is pointing out with wait()/notifyAll(). Another one is to use a CountDownLatch:
In the UI thread create a latch: CountDownLatch latch = new CountDownLatch(1);
Subclass AsyncTask so that it takes a latch in the constructor and save it to a reference mLatch
in doInBackground(), when you need to wait call mLatch.await(). This will block the AsyncTask
in the UI, when the event you're waiting happens, call latch.countDown()
You should be good to go from here.
My opinion is going to be different...
my AsyncTask should wait till event in the UI-thread happen.
AsyncTask's are great for long running operations like http downloads, long i/o operations, image resizing, or any cpu intensive operation that would freeze the UI thread.
However, Android runs AsyncTasks sequentially and not in a pool by default. More details here.
So if you have an AsyncTask that runs indefinitely, such as waiting for a UI action, you could likely block other AsyncTasks from running. Leading to more deadlock and threading problems.
I would suggest any of the following:
Use a different Executor for your AsyncTask so it runs similarly as it does today, but not to conflict with other AsyncTask items. This is the easiest approach.
Split your AsyncTask up into multiple tasks. The first one does whatever your current AsyncTask does up until the wait. The second one does whatever your current one does after the UI event. The latter task gets queued by the UI that generated the event.
Use a dedicated Thread. Use the Handler class to marshall events back from the thread to the UI thread as appropriate.
AsyncTask is introduced for running things which takes long time. In earlier android OS, it can be done in main thread or UI thread. But now android forces us to do long running things in AsyncTask to make UI thread responsive. If you want during AsyncTask your android UI do nothing then you can simply add progress Dialog during it. Start progress Dialog in onPreExecute() & end it in onPostExecute(String[] result).
Sample code : in AsyncTask
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("Loading, please wait...");
dialog.setIndeterminate(true);
dialog.show();
}
#Override
protected void onPostExecute(String[] result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
// do something with result
}
Thanks
I have an Android App that uses an RPC mechanism to set/get information to/from a server. I call the RPCs from whithin the main thread (blocking) and I want them to be blocking. However, sometimes a call can last for some seconds and I'd like to display an indeterminate progress dialog after some specified time (e.g. 1 second).
I tried to spawn a new thread that makes the call and the main thread waits in a loop (with sleeps) until the call has been finished. Inside this loope I show the progress dialog but this is not working.
Is it possible to show and update the progress dialog inside another Thread or does anybody know a better solution that allows me to use blocking calls?
You cannot do both, make the main thread wait in a loop and show a progress dialog, at the same time. Either the main thread waits or shows the dialog.
Why do you want to block the main thread? Communication over the internet should always be done in a background thread because you never know how long it will take to complete. Do that stuff in AsyncTask and show the progress dialog in main.
Try using AsyncTask. It is an android mechanism which is used to make such network calls. Get the brief detailing of AsyncTask here:
Using AsynTask to show progress bar while attempting to SSH to Server
Using a AsyncTask you can block the user from proceeding ahead. You have to show a progress dialog in the onPreExecute() method of the AsyncTask. All your network related activities will take place in doInBackground(). After the background action is completed there will be a call to onPostExecute() where the progress dialog will be dismissed.
AsyncTask is a asynchronous call because you have 2 threads working simultaneously, one is the UI thread on which you are showing your progress dialog and the other is the non-ui background thread which is fetching your data from the server.
Hope this explanation helps.
I have found a solution that seems to work (at least I havent noticed any problems yet). I know the proper way would be to use somethn like AsyncTask but in my case I have no benefit from it and it complicates the program logic.
To update the UI within a new thread:
new Thread()
{
public void run()
{
Looper.prepare();
... do UI stuff here
Looper.loop();
}
}.start();
I need advice about ProgressDialog , I show dialog like
pd = ProgressDialog.show(
Dashboard.this,
"LOADING...",
"PLEASE WAIT", true, false);
and it shows, but it when in background is intensive calculation that circle stops to spin ( like it is blocked). I am running this code above inside onClick button. What to change to avoid this blocking or that is impossible ?
You have to move your intensive calculation to another Thread, to not block UI thread
see another SO question for example how to use AsyncTask and ProgressDialog together
progressDialog in AsyncTask
When you say your progress dialog does not spin, it actually means that your intensive calculation is blocking the main /UI thread
you should make use of an Asynctask
Also get a hang of painless threading in android
It will run in the background without causing hiccups in the UI thread...
Since android apps run on a single main (UI ) thread, you should avoid doing heavy tasks on the UI thread
An asynctask is basically an intelligent worker thread provided by the android system.. It contains helper methods wherein you can easily decide what you want to do
A progress dialog should be created in onPreExecute() and dismissed in onPostExecute()
Do intensive task in doInBackgound()
Here are some tutorials:
easy to understand asynctask
I noticed a similar problem for dot NET, but my problem is for Android, so perhaps solution looks different.
The process is activated by clicking button. The process was running as part of UI thread and at the end it did updating UI. I have added progress dialog to be more user friendly, so I instantiate a thread running the process and at the end it updates UI and dismisses progress dialog. Unfortunately UI update is failing with the exception below:
07-19 21:14:04.602: ERROR/Atjeews(283): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
If I try to block UI thread and release it after long process finishes to update UI, the progress dialog doesn't get shown. Should I try to show progress dialog in a separate thread instead, or there is another simpler solution?
please check http://developer.android.com/resources/articles/painless-threading.html
Taken from the Android Developers Processes and Threads page:
To fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
You can just instantiate an anonymous Runnable as the argument, like post(new Runnable(){doWhatever();}), that will do whatever you want on the UI thread instead.