0

We developed a new version of an application back in October and this problem was not noticed at the time, so probably didn't occur. This code has not changed, but what has changed is the versions of Android. We're even seeing this on devices running 4.4.2, so it's not just a lollipop issue.

I have a "static" class that is used throughout the application to show and close progress dialogs. The relevant methods from that class are included in the code block below. I've added some timing around the API call that's in question and also included the result from a couple of calls. progressDialog is a static field on the class used to track the currently opened dialog so it can be closed.

/**
 * Shows the progress dialog box, allowing for the message and title to be supplied.
 * The progress dialog will be indeterminate and not cancelable.
 *
 * @param context The context that owns the dialog.
 * @param message The message to display in the dialog.
 * @param title   The title for the dialog box.
 */
public static void showProgressDialog ( Context context, String message, String title ) {
    closeProgressDialog();
    String actualTitle = OverrideProgressDialogTitle ? DefaultProgressDialogTitle : title;
    String actualMessage = OverrideProgressDialogMessage ? DefaultProgressDialogMessage : message;

    Date start = new Date();
    progressDialog = ProgressDialog.show( context, actualTitle, actualMessage, true, false );
    Date end = new Date();

    Log.v( LogTag, String.format("It took %s minutes to show the dialog.", DateUtils.millisecondsToMinutes( end.getTime() - start.getTime() ) ) );
}

/**
 * Closes the progress dialog box if it is opened.
 */
public static void closeProgressDialog () {
    if ( progressDialog != null && progressDialog.isShowing() ) {
        try {
            progressDialog.dismiss();
        }
        catch ( Exception e ) {
            Log.e( LogTag, "Error closing dialog.", e );
        }
    }
    progressDialog = null;
}

Here are some timings:

It took 0.0013666668 minutes to show the dialog. 
It took 3.8333333E-4 minutes to show the dialog. 
It took 3.6666667E-4 minutes to show the dialog. 
It took 1.4308 minutes to show the dialog.

The result is very repeatable... the first time in the app on 2 particular screens when the dialog is shown, it takes about 1.5 minutes to return from the call to ProgressDialog.show but subsequent calls to show the dialogs from those same places return almost immediately. In one case, the dialog is being shown from the onStart method of a fragment to load data, in the other case it is being shown when a button is clicked that submits data to the server.

Has anyone seem this method call take a long time to return and if so, how did you resolve it?

EDIT: I actually tracked this down further and it's some other issue causing the hang up. There seems to be at times a long delay between when an AsyncTask's onPreExecute method completes and when doInBackground begins.

Dewey Vozel
  • 2,257
  • 1
  • 19
  • 22
  • By holding a static reference to a ProgressDialog you're leaking the Activity Context, which can cause all kinds of trouble. – Egor Jul 08 '15 at 19:01
  • The dialog is always opened and closed within the same activity, so there should be no leaking. – Dewey Vozel Jul 09 '15 at 10:01

2 Answers2

1

Happened to me some weeks ago.

On some devices, showing a Dialog statically caused lots of pain, while in others, none.

It was directly related with the Context being used.

I'd recommend you to not use that ProgressDialog, but create your own DialogFragment and use a FragmentManager to show it or to hide it.

It fixed this exact same issue for me.

Reinherd
  • 5,476
  • 7
  • 51
  • 88
0

Have you checked Progress dialog UI Freezes/Slow or Progressdialog slow to show in Android ? It is very likely a threading issue. As in: you might be calling show/hide from a background thread.

[original post:] A static class to track progress dialogs is bad design. Don't do it.

You're not supposed to close progress dialogs from (potentially) different contexts, because they might be in a different view hierarchy (attached to a different Activity) and this view hierarchy might already be destroyed/detached.

Community
  • 1
  • 1
ByteWelder
  • 5,464
  • 1
  • 38
  • 45
  • I disagree that following DRY to cut out repetitive boilerplate code and logic is bad design. I understand there can be an issue with leaks, etc if used incorrectly, but the dialogs are always opened and closed from within the same context. This should not be the cause of the problems we're seeing. – Dewey Vozel Jul 09 '15 at 10:00
  • I have nothing against DRY. DRY can be implemented without keeping track of dialog instances. There are many ways to reduce boilerplate code, but keeping track of context-bound instances this way is just bad code design. You're supposed to design your code in such a way that you can't use it incorrectly - or that when it is used incorrectly, you provide clear feedback of what went wrong (e.g. through exception throwing). In any case: anything that isn't obvious and self-documenting should be clearly documented with javadoc. – ByteWelder Jul 10 '15 at 09:22
  • I'm not defending or condoning my use of the static class for managing the progress dialog, but here is why and how I'm using it this way. It's a pretty standard pattern I think for an activity OR fragment to perform a network operation either when it starts / resumes or in response to some user interaction. This app does it using AsyncTasks and in the onPreExecute the progress dialog is shown. In the onPostExecute, the progress dialog is dismissed and the message is sent to the handler. If anything needs to change globally about the progress dialogs being shown, it can be done in one place. – Dewey Vozel Jul 18 '15 at 17:22