Threads and ProgressDialog - android

I am developing my first Androïd application and I'm facing a problem when I want to display a ProgressDialog to indicate that a process is being run.
In my application, the user triggers a time consuming task by pressing a Button. The "OnClick" function of my "OnClickListener" is called when the user presses the Button. In this function, here is what I'm currently doing :
- creation and configuration of an instance of the ProgressDialog class,
- creation of a thread dedicated to the time consuming task,
- attempt to display the ProgressDialog using the "show" method,
- start of the thread,
- main Activity suspended (call of the "wait" function)
- wake up of the main Activity by the thread when it is finished
- removal of the ProgressDialog by calling the "dismiss" function.
Everything works fine (the result of the long task is correct) but the ProgressDialog nevers appears. What am I doing wrong?
Thanks in advance for the time you will spend trying to help me.

You should not call wait() to the Main Activity/UI thread, because this is actually freezing the UI including your ProgressDialog, so it has no time to fade in and will never be shown.
Try to use multithreading correctly: http://developer.android.com/resources/articles/painless-threading.html
final Handler transThreadHandler = new Handler();
public void onClick(View v) {
// show ProgressDialog...
new Thread(){
public void run(){
// your second thread
doLargeStuffHere();
transThreadHandler.post(new Runnable(){public void run(){
// back in UI thread
// close ProgressDialog...
}});
}
}.start();
}

I would suggest using AsyncTask, as it's purpose is exactly to handle this kind of problem. See here for instructions how to use it. Note that the linked page in Floern's answer also recommends the use of AsyncTask.
You would need to do the following:
subclass AsyncTask
override it's onPreExecute() method to create and show a ProgressDialog. (You could hold a reference to it in a member of your subclass)
override it's doInBackground() method to execute your time consuming action.
override it's onPostExecute() method to hide your dialog.
in your activity, create an instance of your subclass and call execute() on it.
If you make your subclass an inner class of your activity, you can even use all of your activity's members.

Related

Android-How to wait for AlertDialog check?

I am creating an AlertDialog using an AlertDialog.Builder and showing it. After showing it, I need to pause application until the user comfirms the Dialog.
I exactly need to pause in a method showing Dialog thread, because its calling method throws a fatal error after return.
Is there any way to do that?
In Android, you can't pause the UI-Thread, as it will result in the OS showing the Application is not responding dialog after about 5 seconds of being paused.
Also, as mentioned by CommonsWare in the comments, Dialogs don't operate in a separate thread.
Without seeing your code it's a bit difficult to answer, but what I could suggest right now is place all the code you need to "pause" in an AsyncTask.
You can place all the code before the pause in the onPreExecute() method, than show your dialog, and in the doInBackground() method, maybe in a while loop or something with volatile variables or something (this code runs on a background thread so it won't stuck the UI-Thread) and then the code after the pause in the onPostExecute() method.
both onPreExecute() and onPostExecute() operates on the UI-Thread. the onPost is called after the doInBackground has finished.
But again, if you'd show some code of the pause it would be easier to help you.
Further reading: AsyncTask
Another way to handle this is to use threads. In a non-UI thread, call your AlertDialog's show() method using the runOnUiThread() method of your Activity. Call Object.wait() in your non-UI thread, and call Object.notifyAll() in your AlertDialog's OnClickListener. The non-UI thread will then wait until the user clicks on your AlertDialog.

Android - show progress dialog while doing work on UI thread

I need to do some work on the UI thread, specifically setting up some views, etc. - this can't be done in a background thread. The process is invoked on a button click and takes about a second or so to complete - without a progress dialog it looks as if the app is frozen. I use progress dialog with AsynTasks in several places and it works fine - however here I'm struggling.
I started with simple:
showDialog(DIALOG_PLEASE_WAIT);
viewInfo.setFromGuide(true); //this method just sets a variable
viewInfo.setVenue(venue); //this method does a lot of UI manipulation and takes a second or so
showScreen(VIEW_INFO); //this method shows the corresponding view in ViewFlipper
dismissDialog(DIALOG_PLEASE_WAIT);
However the dialog would not show (sort of expected, as this is all on UI thread.
Then I changed the code to this:
Handler hnd = new Handler() {
#Override
handleMessage(Message m) {
viewInfo.setFromGuide(true);
viewInfo.setVenue(venue);
showScreen(VIEW_INFO);
dismissDialog(DIALOG_PLEASE_WAIT);
}
}
showDialog(DIALOG_PLEASE_WAIT);
new Thread() {
public void run() {
hnd.sendEmptyMessage(0);
}
}.start();
This still doesn't show the dialog - naturally, the UI work in handleMessage is still done on the UI thread. So, what can I do to show the progress dialog?
If it takes really takes a second or so to complete than maybe you can just use a simple Toast notification with a message like "Please wait"
as you are using AsyncTask you can override onProgressUpdate which is called when ever you call publishProgress() from inside the doInBackGround so you can publish your results smoothly while working in background because, onProgressUpdate works on the UI thread.

Android problems with out-of-order multithreaded processing and dialogs

I seem to have consistent problems with timing threads and dialog windows. I've tried using a thread, or onCreate/onPrepare, or an AsyncTask to do some downloading/processing in the background. More often than not, when the background processing completes and dismisses the dialog window, control seems to return to the root thread (Activity/UI thread?) before the dialog is gone or the onPostExecute-like process is done. This makes me think I'm doing it incorrectly. Here is a typical structure (pseudo-code):
public class X {
protected String result = null;
protected ProgressDialog progressDialog;
public void onCreate() {
...
new XTask().execute();
progressDialog.show();
// result is null here, should be "hi"?
// do things with result, like barf on a NPE...sigh
}
private class XTask extends AsyncTask {
protected doInBackground() {
// Get URL.
// Look at contents, takes a few seconds.
// Return the result (should get sent to onPostExecute).
}
protected onPostExecute(r) {
result = r;
progressDialog.dismiss();
}
}
}
I would think that, after doPostExecute sets result and dismisses the dialog, processing then continues in the onCreate method. However, result is often (not always) null at this point in onCreate. Is there a better way to do this? Is this just due to the general crappiness of the emulator?
Thanks.
Edit: To be more concrete, my task (in doInBackground) fetches a URL and does a little processing on the response. This process takes 1-3 seconds. Then, theoretically, onPostExecute sets X.result to what was fetched. I know the URL content is valid and the response is good (not null). The problem is that during those 1-3 seconds, control returns to onCreate, as if the progressDialog never lived at all (it doesn't get displayed in the emulator at all, but that's normal I guess).
I had thought that calling dialog.show() was a blocking method, i.e., the dialog appeared and that method wouldn't continue until it disappeared, but that doesn't seem to be the case. Either my progressDialog.dismiss() is getting called before it should, before setting X.result, or not getting called at all, or dismiss() is happening faster/before the assignment, or something else entirely is going wrong...
Changing the order of the execute and progressDialog doesn't help, nor does moving it into onPreExecute(). Strangely, onPostExecute doesn't get called until I return in onCreate. If I have a Thread.sleep loop after execute (I thought giving it time would help), it never finishes the task until that loop finishes and I return. e.g.:
new XTask().execute();
int z=0;
while (response == null && z < 50) {
Thread.sleep(500);
z++;
}
if (response == null) return;
The task's onPostExecute method doesn't get called until "return". Hmmm...maybe being in onCreate is affecting it.
A ProgressDialog is usually used to block user interaction during loading or heavy processing but the main UI thread will continue to execute.
If you wish to perform some operation on the result you must do it in either onPostExecute of XTask or after you have gotten the result in doInBackground.
private class XTask extends AsyncTask {
#Override
protected void onProgressUpdate(/*params*/){
//modify UI
}
protected doInBackground() {
// Get URL.
// Look at contents, takes a few seconds.
//Option A: Now have the result, do some other processing here
//Cant modify UI components from here, If you need to modify a UI component from
//here call publishProgress() and modify the component in onProgressUpdate()
// Return the result (should get sent to onPostExecute).
}
protected onPostExecute(r) {
result = r;
//Option B do some processing on the result
//You can modify UI components from here
progressDialog.dismiss();
}
}
I would show the progress dialog before triggering the AsyncTask. Normally, when an AsyncTask gets executed, it takes a while to finish itself and in that time, the rest of the task calling method has already run. But in your case the task returns instantly which is probably why the dialog shows up AFTER the postexecute gets called under the AsyncTask.
I would think that, after doPostExecute sets result and dismisses the dialog, processing then continues in the onCreate method.
This is not true, when you call new XTask().execute() in UI thread, application create a worker thread and start running whatever you defied in AsyncTask.doInBackground() on this work thread, at this point (after calling new XTask().execute()), UI thread continue execute code after new XTask().execute().
The point you are talking about where your work thread finish and return to UI thread is AysncTask.onPostExecute(), this method is guaranteed to be called on UI thread after AsyncTask finish. this is the reason why it is called AsyncTask. Both of UI thread and work thread are running asynchronously.
If you want to make your UI thread blocked and wait for AsyncTask finish after XTask().execute(), you can to this:
XTask xTask = new XTask();
xTask.execute();
progressDialog.show();
xTask.get() // <-- this will make your UI thread blocked and wait for AsycnTask at this point
// result is null here, should be "hi"?
This is possible but not a good practice, as AsyncTask.get() will block execution on calling thread so probably get ANR exception.
To sum up
1. AysncTask.onPostExecute() is where process return from worker thread to UI thread, we don't care where and when it will be called on UI thread, we just need ensure it will be called on UI thread properly at some point in the future.
2. AsyncTask.get() by calling this method actually make you AsyncTask running synchronously with the calling thread.
Putting code into the task's onPostExecute should work, a simple test suggests it will (for me). However, I ended up writing a different solution which also works. I put most of the code into a Handler on the activity, which separates it from the UI thread entirely. My onCreate simply shows the loading ProgressDialog window and that's it--it just sits there, "loading". The background task does its thing and when finished, sends a message to the handler. This message tells the handler to dismiss the loading dialog and populate the list. If there are errors, different messages are sent and the handler shows an error dialog.

Android - Starting a thread crashes app

I've got a few activities. In the main activity I have a login screen, when the user presses the login button, a thread is started to show a progress dialog until the user has been authenticated. At this point i load the next activity which has several fields for the user to input data.
Here the user inputs some data and presses a button to process it. The data is passed to a new activity where the data is actually processed and displayed. This is where i create the new thread and where it's crashing when i call thread.start(); and I have no idea why this is happening.
Both activities are implementing Runnable.
I'm using the same code below to create and call thread.start() in the button press of the first activity and the onCreate method of the last one:
pd = ProgressDialog.show(search_results.this, "", "Searching...", true, false);
Thread thread = new Thread(this);
thread.start();
I'm using the same code below as well to handle the threads for both as well.
public void run() {
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
pd.dismiss();
}
};
Am I missing something? I don't really understand why it's crashing.
While I encourage people to use AsyncTask, it's not really needed, especially for simple things like progress/loading dialogs. That's not the problem here.
Your question and your code is confusing. I'm not sure which code goes where, on which activity, and I hope you're not leaving dialogs open between activities, trying to access them across them (it won't work, of course). Also, providing a Context to a Thread does not even compile (it's marked with errors at design time). To sum it all up, you didn't provide the Log entry. Sorry, I can't make sense of what you're doing or where the error is. We can only guess.
Below are one of the possible ways to do it with a Handler, a Runnable and a Thread. This was taken from the Developer Resource when I first learn how to use it:
1- You declare a Handler. Most people do this on the onCreate section to reuse it often:
Handler mHandler = new Handler();
2- When you need, you start a Thread:
new Thread() { public void run() {
mHandler.post(mLoadingData);
// ... do work
mHandler.post(mLoadingDataStop);
}}.start()
3- These are the Runnables that are posted to the Handler:
private final Runnable mLoadingData = new Runnable() {public void run() {
showDialog(LOADING_DIALOG); // In your case, show your custom dialog
}};
private final Runnable mLoadingDataStop = new Runnable() {public void run() {
dismissDialog(LOADING_DIALOG); // In your case, dismiss the dialog
}};
For a progress dialog, things need a bit more work (update the progress etc.), but for a loading dialog, you don't need to really mess with messages.
I had this same issue when developing for the tablet. After a certain API, I'm thinking 3.0 (sdk 11), Android enforces applications to run long running processes on a separate thread, otherwise it kills it. Logcat will confirm this.
I know you are using another thread, but that didn't work for me either. Try using AsyncTask. You can create a quick inner class that, in my opinion, is way easier than handling your own threads. AsyncTask has several functions that run on the UI thread and a couple that run on their own thread. This allows you to start a "Loading" user interface object on the user interface thread, process on the back end thread, and then when its done, it'll notify a user interface thread function.
You'll want to specifically look at override
onPreExecute()
doInBackground()
onPostExecute()

A few questions about ProgressDialog in Android

1) FOA PD (ProgressDialog) can be created only from Activity, doesn't it? Please provide an useful example if it is really not.
2) If a PD should be created in separate thread could it be created and showed if it's thread doesn't do anything at all? I mean something like this (assuming mProgressDialog is a property of the class):
new Thread(){
public void run(){
mProgressDialog = ProgressDialog.show(appContext,
appContext.getResources().getString(R.string.progress_wait),
appContext.getResources().getString(R.string.progress_db_installing),
true);
}.start();
As I understand the thread dies immediately after executing run() cause there is nothing to do and so PD doesn't show. It should have some processing code or at least an empty cycle with some manageable condition
3) if PD should be created in the main thread should it be created only at the end of OnCreate() method or in the body of some method called/caught(by some Listener) started in OnCreate() method?
4) PD by itself doesn't suspend any thread while displaying, does it? So the code continues executing after the show() method . I mean the show() by itself doesn't suspend/pause the thread cause I guessed it does.
1) Not sure how it's relevant unless you can come up with a reason to create a ProgressDialog outside of an Activity context; I think the answer is "no," though.
2) No, you can't create a dialog from a background thread directly. Have you tried your code? It'll die with an exception with a helpful traceback. See any one of a number of SO questions about how to call back to the UI thread to do things like show dialogs.
3) You can create it anywhere in your activity; for example, it's common to do this in onPreExecute() in an AsyncTask, which may be triggered from an onClick callback.
4) No.

Categories

Resources