Friday, August 7, 2009

Android: displaying one dialog after another

So having got my progress bar dialog to appear I now find myself prevented from displaying a second dialog to announce the results of the long running action.

Here is the code:

   final ProgressDialog myOtherProgressDialog = new ProgressDialog(
     this);
   myOtherProgressDialog.setTitle("Please Wait ...");
   myOtherProgressDialog.setMessage("Adding item to study list ...");
   myOtherProgressDialog.setIndeterminate(true);
   myOtherProgressDialog.setCancelable(true);

   // TODO spinner not showing for some reason ...
   final AlertDialog dialog = new AlertDialog.Builder(this).create();

   final Thread add = new Thread() {
    public void run() {
     AddItemResult add_item_result = addItemToList(
       Main.default_study_list_id,
       (String) item.item_node.atts.get("id"));
     
     dialog.setTitle(add_item_result.getTitle());
     dialog.setMessage(add_item_result.getMessage());
     dialog.setButton("OK",
       new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog,
          int which) {
        
         return;
        }
       });
     
     myOtherProgressDialog.dismiss();
     //Looper.prepare();
     dialog.show();
    }
   };
   myOtherProgressDialog.setButton("Cancel",
     new DialogInterface.OnClickListener() {
      public void onClick(DialogInterface dialog, int which) {
       add.interrupt();
      }
     });
   OnCancelListener ocl = new OnCancelListener() {
    public void onCancel(DialogInterface arg0) {
     add.interrupt();
    }
   };
   myOtherProgressDialog.setOnCancelListener(ocl);
   closeMenu();
   myOtherProgressDialog.show();
   add.start();

The problem is that if I just try to show the second dialog I get this error:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

and if I try and edit the existing progress dialog to show the results of the long running action I am told:

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Which is a bit frustrating. Is my only option to display results in a completely new activity?

Android dialog not appearing after menu action

So I have been having reasonable success getting progress dialogs to show up in android. It all seems to rely on showing the progress dialog and then starting whatever is the long running process in another thread, e.g.

 private void loadItem(Activity activity, final String item_id) {
ProgressDialog myProgressDialog = new ProgressDialog(activity);
myProgressDialog.setTitle("Please Wait ...");
myProgressDialog.setMessage("Loading item ...");
myProgressDialog.setIndeterminate(true);
myProgressDialog.setCancelable(true);

final ItemDownload item_download = new ItemDownload(activity,
myProgressDialog) {
public Vector downloadCall(SmartFmLookup lookup) {
return lookup.item(item_id);
}
};
myProgressDialog.setButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
item_download.interrupt();
}
});
OnCancelListener ocl = new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
item_download.interrupt();
}
};
myProgressDialog.setOnCancelListener(ocl);
myProgressDialog.show();
item_download.start();
}


I've even managed to support user cancellation. All good; however I have a more complex situation where the progress dialog is supposed to be displayed after hitting a menu button, and then replaced with another dialog that shows the results of the process; which is followed by a second progress dialog. In this case the first progress dialog never appears but the result dialog and second progress dialog do. I've tried removing all the other dialogs, but the initial progress dialog still never shows up - it gets stuck on the clicked menu button (see image).

Here's the code with subsequent dialogs stripped out:


public boolean onOptionsItemSelected(MenuItem menu_item) {
switch (menu_item.getItemId()) {
case ADD_TO_LIST_ID: {
// send command to add to list - need spinner?

final ProgressDialog myOtherProgressDialog = new ProgressDialog(
this);
myOtherProgressDialog.setTitle("Please Wait ...");
myOtherProgressDialog.setMessage("Adding item to study list ...");
myOtherProgressDialog.setIndeterminate(true);
myOtherProgressDialog.setCancelable(true);

// TODO spinner not showing for some reason ...

final Thread add = new Thread() {
public void run() {
AddItemResult add_item_result = addItemToList(
Main.default_study_list_id,
(String) item.item_node.atts.get("id"));

}
};
myOtherProgressDialog.setButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
add.interrupt();
}
});
OnCancelListener ocl = new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
add.interrupt();
}
};
myOtherProgressDialog.setOnCancelListener(ocl);
myOtherProgressDialog.show();
add.run();


break;
}
}
return super.onOptionsItemSelected(menu_item);
}


I think the solution must require programmatic closing of the menu popup. I did find this post on how to open it.   I was hoping to use that to open the menu bar at the beginning of my app, but calling that from the OnCreate method causes this error:

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?

However it seems I can use something similar to close the menu panel:


    public void closeMenu(){
        this.getWindow().closePanel(Window.FEATURE_OPTIONS_PANEL);
    }

However, even after shutting the open menu panel, I still don't get to see the progress dialog.

Ah, found the problem, I was calling add.run() instead of add.start, so the new Thread was never spawned. Duh!!!