1

I have a class which extends AsyncTask, which is intended to serve as a generic task manager class for my application.

Problem:The strange behavior is that the progress dialog shows up, but is never dismissed.

  • I am sure that onPostExecute() gets called for every task instance, as any Log.d("","") statements fire if placed in here, even the Toast messages show up from within this method, but I am not able to dismiss the static dialog.

  • I understand that AsyncTask(s) have access to UI thread at only 2 places [onPreExecute() and onPostExecute()], so I think trying to dismiss the dialog in runOnUiThread() is unnecessary.

  • All calls to executeTask() are made from different onCreate() methods of different activities that need to fetch some data over network before populating some of their UI elements, and I always pass the current activity's context to the tasks.

  • As I do not switch activities until after the related tasks are completed, I believe the activity context objects are still valid (am I wrong to have assumed this???) I have never found any of them to be null while debugging.

  • Could this be a timing issue? I have also observed that most of the times DDMS shows all tasks get completed before the activity is displayed. If I use new Handler().postDelayed(runnable_which_calls_these_tasks,10); in the onCreate(), and add delaying code in foo_X(), the activities are displayed without any delay, but the dialog will just not dismiss().

I have read through quite a number of articles on this issue but am still not able to figure out exactly where am I going wrong. I do not want to define each task as private inner class Task1 extends AsyncTask<> in all of my activity classes and I would not want to (unless this is the only solution) load my application object with all activity references either as mentioned in this discussion: Is AsyncTask really conceptually flawed or am I just missing something?.

I have spent a week on this and am absolutely clueless :( It would be great if someone can guide me, and let me know what am I missing.
Following is the class definition: [I've removed some irrelevant application specific code for clarity]

public class NetworkTask extends AsyncTask<Void, Integer, Boolean> {  

private  Context UIcontext;  
private int operationType;  
private static ProgressDialog dialog;
private static int taskCount;


private NetworkTask(int operationType Context context){  
    this.UIcontext = context; 
    this.operationType = operationType;
    if (taskCount++ == 0)  
        dialog = ProgressDialog.show(context,"","Loading...");

}  

public static Boolean executeTask(int operationType, Context context) {
    return new NetworkTask(operationType, context).execute().get(); 
}

@Override  
protected void onPreExecute(){  
    super.onPreExecute();  
    if (taskCount == 1)  
        dialog.show();  
}  

@Override
protected Boolean doInBackground(Void... arg0) {  
switch(operationType){  
    case TYPE_1:  
        foo1();  
        break;  
    case TYPE_2:  
        foo2();  
        break;  
    case TYPE_3:  
        foo3();  
        break;  
    case TYPE_4:  
        foo4();  
        break;  
}  

@Override
protected void onPostExecute(Boolean result) {
    super.onPostExecute(result);
    taskCount--;
    if (dialog.isShowing() && taskCount == 0){
            dialog.dismiss();
    }else {
        Toast.makeText(UIcontext, "Task#"+ operationType+", m done, but there are "+taskCount+" more", 5).show();
    }
}

}

Community
  • 1
  • 1
ritwaj
  • 15
  • 1
  • 6

1 Answers1

2

Edited:

Mystery solved - this one was giving me a bit of trouble. There were a few problems:

  1. The main problem why dialog was not showing was NetworkTask.get(). This is a blocking call that waits for the whole NetworkTask to finish. During that time it blocks UI thread so nothing is drawn (also other UI elements are unresponsive). Remove get():

    public static Boolean executeTask(int operationType, Context context){
        new NetworkTask(operationType, context).execute();
        return true; // return whatever
    } 
    
  2. The show() on ProgressDialog is called twice. This shows two dialogs, one after another. Remove show() inside onPreExecute().

  3. ProgressDialog is modal - it prevents changing UI until it is done. Toast.makeText() are called before dialog.dismiss() but since dialog is blocking drawing to screen, they get queued and are shown after dialog is dismissed.

  4. super.onPostExecute(result) and super.onPreExecute() are redundant so can be removed.

I can post the whole working code if you have trouble with it.

Peter Knego
  • 79,991
  • 11
  • 123
  • 154
  • @Peter As I mentioned earlier, I want to manage all of my network tasks centrally by using this class. task count is just a static counter associated with the class [decremented on every task return , and incremented at every task spawn]. My intention is that the progress dialog is shown by the first task and dismissed by the last one. [ just rechecked, taskCount is static in my code, sorry for the typo here] – ritwaj Nov 15 '10 at 17:11
  • @Peter Changed the code based on your observation, making sure that dialog is shown and dismissed exactly once. The dialog doesn't show up at all. – ritwaj Nov 15 '10 at 17:26
  • Please update the code above to reflect the changes you made. – Peter Knego Nov 15 '10 at 17:51
  • @Falmarri for testing purposes I changed all fooX() to look like this `private void foo1() { try { Thread.sleep(15000); }catch (Exception e) { } // network tasks done here}` shouldn't this ensure that tasks will take way too much time to execute therefore each onPostExecute() is called after a long time? UI elements load up, there is a significant delay (due to sleeping thread) and then the toasts appear, but I don't see the dialog. – ritwaj Nov 15 '10 at 21:37
  • @Peter Awesome! works like a charm now :) Now I understand why the activity was taking ages to load despite separating lengthy operations as AsyncTask. With get() I was effectively executing all of my operations serially. A quick question though, can you point out an instance when we would want to use `get()`? Doesn't blocking indefinitely defeat the purpose of AsyncTask altogether? To me, `get(long timeout, TimeUnit unit)` makes much more sense, as we can probably "afford" to wait for some time, in the context of our application. Thank you again for your patience :) – ritwaj Nov 16 '10 at 00:46