0

Good day! Mr. Spock here.

I have created an ErrorListener for my Android MediaPlayer. If I try to display an AlertDialog from my handler, it causes a "leaked window" exception to occur when the "OK" button is pressed on the dialog. Here are the relevant code snippets:

Class definition:

public class PlayMediaActivity extends Activity implements OnPreparedListener, OnErrorListener, MediaController.MediaPlayerControl

Creating MediaPlayer:

mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnErrorListener(this);

mediaController = new MediaController(this);

try {
mediaPlayer.setDataSource(URL);
mediaPlayer.prepareAsync();
mediaPlayer.start();
}
catch(...) {} // Omit real code for brevity.

MediaPlayer prepared listener:

public void onPrepared(MediaPlayer mediaPlayer) {
    Log.d(TAG, "onPrepared");
    mediaController.setMediaPlayer(this);
    mediaController.setAnchorView(findViewById(R.id.main_audio_view));

    handler.post(new Runnable() {
      public void run() {
        mediaController.setEnabled(true);
        mediaController.show();
      }
    });
  }

MediaPlayer error listener:

public boolean onError(MediaPlayer mp, int what, int extra) {

    ShowDialog("Unable to play audio. Try again later.");

    return true;
} 

ShowDialog routine:

private void ShowDialog(String message) {
    // Alert the user something went wrong.
    ContextThemeWrapper cw = new ContextThemeWrapper( PlayMediaActivity.this, R.style.AlertDialogTheme );
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder( cw );

    alertDialogBuilder.setTitle("Oops!");

    // set dialog message
    alertDialogBuilder
            .setMessage(message)
            .setCancelable(true) // Allow back hardkey to dismiss
            .setPositiveButton("OK",new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog,int id) {
                    // if this button is clicked, close current activity
                    dialog.dismiss();
                    PlayMediaActivity.this.finish();
                }
              });

    alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {  // Catch back key press.        
        @Override
        public void onCancel(DialogInterface dialog) {
            //do whatever you want the back key to do
            dialog.dismiss();
            PlayMediaActivity.this.finish();
        }
    });

    // create alert dialog
    AlertDialog alertDialog = alertDialogBuilder.create();

    // show it
    alertDialog.show();
}

When I call ShowDialog from the onError routine, it pops up, but when I press the "OK" button the activity is stopped and destroyed but the dialog is leaked (according to the stack trace), even though I'm calling dismiss() before finishing the activity.

There are quite a few stackoverflow posts on this kind of topic, but none have solved my problem. I'm pretty new to Android development and my guess is I'm doing something fundamentally wrong but I can't put my finger on it.

Does anyone see what the problem might be?

EDIT 1 - Including StackTrace:

04-14 14:38:08.089: E/WindowManager(2099): Activity com.lcboise.lifechurch.PlayMediaActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@405619f8 that was originally added here
04-14 14:38:08.089: E/WindowManager(2099): android.view.WindowLeaked: Activity com.lcboise.lifechurch.PlayMediaActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@405619f8 that was originally added here
04-14 14:38:08.089: E/WindowManager(2099):  at android.view.ViewRoot.<init>(ViewRoot.java:259)
04-14 14:38:08.089: E/WindowManager(2099):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
04-14 14:38:08.089: E/WindowManager(2099):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
04-14 14:38:08.089: E/WindowManager(2099):  at android.view.Window$LocalWindowManager.addView(Window.java:424)
04-14 14:38:08.089: E/WindowManager(2099):  at android.app.Dialog.show(Dialog.java:241)
04-14 14:38:08.089: E/WindowManager(2099):  at com.lcboise.lifechurch.PlayMediaActivity.ShowDialog(PlayMediaActivity.java:133)
04-14 14:38:08.089: E/WindowManager(2099):  at com.lcboise.lifechurch.PlayMediaActivity.onError(PlayMediaActivity.java:237)
04-14 14:38:08.089: E/WindowManager(2099):  at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:1456)
04-14 14:38:08.089: E/WindowManager(2099):  at android.os.Handler.dispatchMessage(Handler.java:99)
04-14 14:38:08.089: E/WindowManager(2099):  at android.os.Looper.loop(Looper.java:123)
04-14 14:38:08.089: E/WindowManager(2099):  at android.app.ActivityThread.main(ActivityThread.java:3683)
04-14 14:38:08.089: E/WindowManager(2099):  at java.lang.reflect.Method.invokeNative(Native Method)
04-14 14:38:08.089: E/WindowManager(2099):  at java.lang.reflect.Method.invoke(Method.java:507)
04-14 14:38:08.089: E/WindowManager(2099):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
04-14 14:38:08.089: E/WindowManager(2099):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
04-14 14:38:08.089: E/WindowManager(2099):  at dalvik.system.NativeStart.main(Native Method)
Mr. Spock
  • 645
  • 1
  • 9
  • 21
  • Why not to use DialogFragment instead http://android-developers.blogspot.ru/2012/05/using-dialogfragments.html – Alexander Kulyakhtin Apr 14 '13 at 20:29
  • I think it may have to do how you are passing your `Context` to your `AlertDialog`. Post the stack trace. – Steven Byle Apr 14 '13 at 20:34
  • RE: Alex - I will take a look at DialogFragment. Thank you for the reference. – Mr. Spock Apr 14 '13 at 20:40
  • RE: Steven Byle - Stacktrace has been added. – Mr. Spock Apr 14 '13 at 20:41
  • Just ran the code for showing the dialog - it doesn't leak for me. What does line `133` point to in your `PlayMediaActivity`? – Darwind Apr 14 '13 at 21:01
  • RE: Darwind - It points to this: `alertDialog.show();` in the `ShowDialog()` routine above. – Mr. Spock Apr 14 '13 at 21:03
  • Does anyone have any debugging techniques I can use on this? The message is telling me I'm not properly releasing the `AlertDialog` dialog somehow, right? Is there some way I can make sure it's gone before my `Activity` is stopped/destroyed? What else can I do besides calling `dismiss()`? – Mr. Spock Apr 14 '13 at 22:39

2 Answers2

0

Try showing your dialog on UI thread:

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        ShowDialog("Unable to play audio. Try again later.");
    }
});
Borzh
  • 5,069
  • 2
  • 48
  • 64
0

I suggest you not to create the AlertDialog.Builder inside a method. It is more recommendable to create it in the Activity's onCreate method, then release the dialog in onDestroy with dialog.dispose(). What your method could do is receive an AlertDialog as parameter, and configure it (positiveButton, negativeButton, title, message, etc.), so the dialog is correctly configured outside the Activity, and its lifecycle is correctly handled to avoid the undesired memory leak

Hope it helps!

voghDev
  • 5,641
  • 2
  • 37
  • 41