I know there are a million similar questions here, but none of the solutions presented there quite addressed the issue I'm having. I have an AsyncTask that loads data from a database. An indeterminate ProgressDialog is displayed while the data is loading (even though in production code it never takes a visibly apparent time to load the database, but just in case someone builds a huge one).
I used to call and dismiss the ProgressDialog directly from the AsyncTask, and it worked fine. The problem is, I'm trying to enforce better separation of concerns and I decided that displaying things to the screen does not fall in the AsyncTask's domain, and really belongs to the activity. So I implemented a callback interface to the activity, and in the activity I have:
private ProgressDialog progressDialog;
#Override
public void onPreExecute() {
progressDialog = ProgressDialog.show(this,"","Loading. . .",true,true);
}
#Override
public void onPostExecute() {
if (progressDialog != null) {
Logger.d("Dismissing progress dialog");
progressDialog.dismiss();
progressDialog = null;
}
}
Logcat shows that I'm reaching that logger line, but the ProgressDialog never dismisses. Is there some reason why I can't do this in a callback?
Most likely what's happening here is that multiple ProgressDialog's are being instantiated.
Therefore, while dismiss() is successfully called, it's not called on the ProgressDialog currently visible on your screen, and you've lost your reference to this visible one since you've overwritten progressDialog with a new object instance.
Try putting Logger.d("New ProgressDialog"); where you are creating a new instance of the ProgressDialog, and you will most likely see this scenario confirmed.
You could probably fix this by using an Array/List to keep track of all of your ProgressDialogs and dismiss the appropriate one when it's corresponding AsyncTask completes, but personally I think this is far more convoluted then your original approach of having each AsyncTask handle their own ProgressDialog's lifecycle.
This work for me:
if(progressDialog == null) {
// initialize your progress dialog object
}
if (progressDialog.isShowing() && progress != null) {
progress.dismiss();
}
Related
I currently have an android application that runs an asynctask when a button on the activity is clicked. While the asynctask is busy processing its task, I want the activity to display an alertdialog (loading...) to let my users know that the app is busy processing the request, and not just frozen or crashed. Currently, I have the code written like this:
LoadingDialogue.java
public class LoadingDialogue {
private Activity activity;
private AlertDialog dialog;
public LoadingDialogue(Activity myActivity){
activity = myActivity;
}
public void startLoadingDialogue(){
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
LayoutInflater inflater = activity.getLayoutInflater();
builder.setView(inflater.inflate(R.layout.loading_dialogue,null));
builder.setCancelable(false);
dialog = builder.create();
dialog.show();
}
public void dismissDialog(){
dialog.dismiss();
}
and this is how I implemented it in my activity:
CustomAsyncTask asyncTask = new CustomAsyncTask();
loadingDialogue.startLoadingDialogue();
String responseString = asynctask.execute().get()
loadingDialogue.dismissDialog();
However, my loading dialog does not show! It works if I just do it without the async task though.
Thanks!
That code is broken in so many ways.
Never use AsyncTask.execute().get(). Doing that gets the result immediately, which turns it from asynchronous to synchronous. Basically at that point there's no reason to make it an async task, just do it in the body. If your response is that you need the result immediately, you don't understand asynchronous programming. Put any code that needs the result in the onPostExecute.
Really forget that get() exists at all. There's one or two cases where it can be useful, but 99% of the time using it is an error.
The android UI only refreshed when the main thread returns to the looper. So doing show dialog, then doing get(), then doing hide it won't work- it won't show until the entire block is done and control is returned to the looper, by which time its hidden again.
Instead, use dialog.show() in onPreExecute and hide in onPostExecute. That will make it work.
It's kind of odd to have a class holding a dialog like that. It's more normal to derive a class from AlertDialog and just show/hide it. Although this isn't necessarily wrong, there's cases where this may be more convenient.
I'm writing an application for Android, which should get some data from the server as soon as it launches.
Between the start of the application and the response from the server (or timeout, if the server is down), the application should display a "waiting" animation.
Thereafter, the normal panel should be shown (if the server responded) or an error dialog box be displayed (if the server didn't respond).
What is the correct place to put this logic into?
MainActivity.onCreate or some other place?
if you want the data loaded only when the app starts for the first time, onCreate() is the right place. if you want to re-loaded every time the app comes into focus (i.e., the foreground), then onResume() is the right place. take a look at documentation on the activity lifecycle for details.
you'll want to take a look into AsyncTask, or Loader+AsyncTaskLoader to understand the right pattern for doing something in the background then updating the UI with the result.
As Jeffrey suggested at first you have to determine when you want to connect to the server? Depending on this you should connect to server in onCreate or onResume.
Now you must remember one thing that you can't do heavey tasks in your manin GUI thread. Else there is a good chance of ANR. So you have to implement this feature in a different thread. For this you can use different Thread, Handler or AsyncTask. You can find a nice doc here
I think it is a suitable situation to use AsyncTask. So here is an example with AsyncTask
private class ServerCommunication extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// show the connecting screen
// or you can do this before calling asyncTask
}
#Override
protected Void doInBackground(Void... params) {
// communicate with server
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// show the second screeen
}
}
and call it using
ServerCommunication pcd = new ServerCommunication();
pcd.execute();
This is just for suggesting the structure. You can definitely use neccessary paramenters or other method also.
I have a few Activities on my app that hit a web service. Since I don't want to hold up the main thread, this code is in an AsyncTask. However, I do not want the user to be manipulating the Activity while the web service is being called, so before executing the AsyncTask I show a ProgressDialog which spins and blocks the screen. In the onPostExecute method of the AsyncTask, the first thing I do is dismiss the ProgressDialog.
This should prevent the user from manipulating the Activity without actually blocking the main thread.
However, I've noticed a few times where the ProgressDialog is never dismissed and the user becomes stuck. The AsyncTask has finished, onPostExcute has executed, but the ProgressDialog is still shown. The ProgressDialog has no chance of ever being dismissed and the user is stuck on the screen. Their only option is to visit the Android Settings app and force stop my application.
Does anyone have any idea why this happens? What can I do to fix it?
Relevant code:
This is how I show the ProgressDialog and launch the task:
mProgress = ProgressDialog.show(this, "", "Syncing...", true);
(new MyAsyncTask()).execute(intUserId);
This is the onPostExcute for the task. There is no "#Override"
protected void onPostExecute(Boolean result) {
if (mProgress != null) {
mProgress.dismiss();
mProgress = null;
}
}
Check this:
Make sure you called asynctack.execute() on UI thread.
Use #Override on onPostExcute() to make sure it's properly defined.
Maybe try showing your ProgressDialog in the onPreExecute() Method?
protected void onPreExecute() {
mProgress = ProgressDialog.show(this, "", "Syncing...", true);
}
Give that a shot and see if it works.
Peter Knego posted the following link in a comment under the OP. CommonsWare's solution seems to work well.
Backround task, progress dialog, orientation change - is there any 100% working solution?
I'm having a small problem handeling ProgressDialog and the suer hitting the home key.
I create my ProgressDialog as follows:
runOnUiThread(new Runnable() {
public void run() {
progressDialog = ProgressDialog.show(this, "",this.getResources().getString( R.string.AProgressMessage), true);
}
});
and dismiss it when I finished downloading stuff of internet.
progressDialog.dismiss();
the problem is when a user hit the home key, sometimes the Thread that calls the dismiss is kille but hte dialog never gets dismissed... therefore when the app relaunches it gets stuck behind a ProgressDialog.
Any ideas ?
I know this thread is quite old, but I think my answer could help many people.
Activity class has an onPause method. So if you call the dialog from the same activity that is being paused, you can use the onPause method to dimiss the dialog.
Make the dialog variable global, and define the onPause method as follows:
#Override
public void onPause(){
super.onPause();
if(dialog!=null)
dialog.dismiss();
}
Why would the Thread be killed?
If the Android system thinks that the memory is low, it will only kill whole processes and not individual threads. Are you sure you always call progressDialog.dismiss(), even if the thread stops because of an uncaught exception (for example)?
By the way, you should probably use AsyncTask instead of doing the thread management yourself, see here.
HI,
Im trying to show a ProgressDialog while the activity is loading.
my problem is that although i completed all the work in the activity
it takes a long time for the activity to load, i suspect this is because i use
multiple views with multiple listviews with custom array adapters inside a viewflipper.
it takes a long time for the UI to show.
how would i go about checking that all the UI inside the activity finished loading?
or is there a way to preload all the activity and the UI?
Thanks,
Use Asynctask
new DownloadTask().execute();
private class DownloadTask extends AsyncTask<String, Void, Object> {
protected void doInBackgroind(Void... arg0){
//Do time Consuming Processing
publishProgres()
return null;
}
protected void onProgressUpdate(Void... arg0){
}
protected void onPostExecute(Void... result){
log.i("AvtivityInfo", "activity finished loading...");
}
}
If you think you need a ProgressDialog because your activity is opening too slowly, you have much bigger problems. Android is likely to kill off your activity with an activity-not-responding error.
You can either get sophisticated and use Traceview to find your performance issue, or you can just experiment. For example, you can skip setting adapters in your ListViews, to confirm that the problem indeed lies there.
Jorgesys had the right answer in his now-deleted entry, from what I can tell. I suspect that loading your adapters is taking the time, perhaps in database queries, and you need to move some of that into AsyncTasks.