0

First time writing an AsyncTask and I seem to have a subtle design flaw that prevents both ProgressDialog, ProgressBar, and even Log.d() from working properly. I suspect that somehow I am not actually creating a new thread/task.

Short: the symptoms

  • A ProgressDialog is created in the constructor, and the code orders Android to show it in onPreExecute(), but the dialog never shows.

  • onProgressUpdate() is supposed to execute whenever I call publishProgress() from within doInBackground(), correct? Well, it doesn't. Instead, it executes when doInBackground() completes.

Long: investigations

Things I have verified through the emulator and, when possible, on a phone:

  • onPreExecute() is definitely called

    • the progress bar is not reset until after doInBackground() completes

    • update_dialog.show() is definitely executed, but the dialog does not appear unless I remove the .dismiss() in onPostExecute(); I imagine dialog is, like the progress bar, not shown until after doInBackground() completes, but is naturally immediately dismissed

    • the code will happily show dialogs when no computation is involved

  • doInBackground() definitely invokes publishProgress()

    • when it does, onProgressUpdate() does not execute immediately! that is, I have a breakpoint in the function, and the debugger does not stop there until after doInBackground() completes! (perhaps this is a phenomenon of the debugger, rather than doInBackground(), but I observe the same symptoms on a mobile device)

    • the progress bar gets updated... only after doInBackground() completes everything

    • similarly, the Log.d() data shows up in Android Monitor only after doInBackground() completes everything

  • and of course the dialog does not show up either in the emulator or on a device (unless I remove .dismiss() from onPostExecute())

Can anyone help find the problem? Ideally I'd like a working dialog, but as Android has deprecated that anyway I'd be fine with a working progress bar.

Code

Here are the essentials, less the details of computation &c.:

Where I call the AsyncTask from the main thread:

if (searching) { // this block does get executed!
   Compute_Task my_task = new Compute_Task(overall_context, count);
   my_task.execute(field, count, max_x, max_y);
   try { result = my_task.get(); } catch (Exception e) { }
}

The AsyncTask itself:

private class Compute_Task extends AsyncTask<Object, Integer, Integer> {

   public Compute_Task(Context context, int count) {
      super();
      current_positions = 0;
      update_dialog = new ProgressDialog(context);
      update_dialog.setIndeterminate(true);
      update_dialog.setCancelable(false);
      update_dialog.setTitle("Thinking");
      update_dialog.setMessage("Please wait");
   }

   protected void onPreExecute() {
      super.onPreExecute();
      update_dialog.show();
      ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
      pb.setMax(base_count);
      pb.setProgress(0);
   }

   protected void onPostExecute() {
      super.onPostExecute();
      update_dialog.dismiss();
   }

   protected void onProgressUpdate(Integer... values) {
      super.onProgressUpdate(values);
      ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
      pb.setMax(base_count);
      pb.incrementProgressBy(1);
      Log.d(tag, values[0].toString());
   }

   protected Integer doInBackground(Object... params) {
      Integer result = compute_scores(
         (boolean[][]) params[0], (Integer) params[1], (Integer) params[2], (Integer) params[3], 0)
      );
      return result;
   }

   public int compute_scores(boolean[][] field, int count, int max_x, int max_y, int level) {
      int result, completed = 0;
      switch(count) {
         // LOTS of computation goes on here,
         // including a recursive call where all params are modified
         if (level == 0)
            publishProgress(++completed);
      }
   }

   ProgressDialog update_dialog;

}
John Perry
  • 2,497
  • 2
  • 19
  • 28

1 Answers1

0

Turns out this is basically the same issue as the one given here. The "fatal" line is this one:

try { result = my_task.get(); } catch (Exception e) { }

Apparently this puts the UI thread into deep sleep. One should not use get() with an AsyncTask unless one is willing to suspend the UI thread. We have to perform a little magic in onPostExecute() instead.

Although it turns out that this was a duplicate, I didn't find it until after I wrote it, because I didn't realize the thread was blocking.

John Perry
  • 2,497
  • 2
  • 19
  • 28