AndroiDev: Leaky Windows

This is one of those errors that popped up on me that initially left me baffled and amused. Once you look up and find out the explanation for “Activity has lead window”, it makes sense, but the idea of an application having “leaky windows” is still quite hilarious to me (unlike memory leaks, which suck and are not humorous at all). Basically, Android is communicating to you that you’ve tried to put a popup in a location that no longer exists, or you don’t have access to. Here’s my error text as an example:

04-11 06:02:01.973: ERROR/WindowManager(1176): Activity org.wikinews.en.wikinewsreader.SubmitBug has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@43801c78 that was originally added here
04-11 06:02:01.973: ERROR/WindowManager(1176): android.view.WindowLeaked: Activity org.wikinews.en.wikinewsreader.SubmitBug has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@43801c78 that was originally added here

Now let me show you the code I used that crashed, and the fixed version. At the end, I’ll explain “why” (to the best of my understanding) this happens the way it does.

The original (crashing) code:
Builder builder = new AlertDialog.Builder(SubmitBug.this);
builder.setTitle("Thank you");
builder.setMessage("Your bug has been submitted to the developers. They may contact you if they have further questions.");
builder.setPositiveButton("Close", null);
builder.show();
finish();

The functional code:
Builder builder = new AlertDialog.Builder(SubmitBug.this);
builder.setTitle("Thank you");
builder.setMessage("Your bug has been submitted to the developers. They may contact you if they have further questions.");
builder.setPositiveButton("Close", new DialogInterface.OnClickListener() {
 public void onClick(DialogInterface dialog, int id) {
  SubmitBug.this.finish();
 }
});
builder.show();

Ok, so first, the difference. As you can see in the first example I use builder to create a pop up box with a “Close” button (which is tied to nothing) and then finish() which will close the activity. The second version of the code is the same builder, but this time the “Close” button gets an OnClickListener that when triggered, will close the activity. If you’re wondering why I did the first way – I’ve been doing procedural programming for a long, long time. I thought that the finish() line wouldn’t be called until the builder window went away. That is, in fact, not the case and the entire cause of the problem.

Put simply, Android files the request to a different portion of the software stack to show the builder, but may not immediately process it. In the mean time, the code for the application continues to run and the very next thing it sees is finish(). So the application initiates the process of shutting down, unaware of the builder window. Of course, that builder window comes back into play, but it is too late because the activity is gone. Hence the window (the builder) has “leaked” out of the area it was supposed to be in.

As an additional note: I’ve seen this error pop up when I used builder (with the OnClickListner finish()) in combination with a try/catch to alert the user of critical errors that require the application be shut down. In my particular case I’m running multiple threads and sometimes have multiple builder popups. One would “finish” the application with the second still on screen and would again cause this error. I worked around that issue by setting a flag to prevent a second builder popup if one had already been shown (after all, the user doesn’t care how many ways the application crashed, just simply that it did) (Editor’s note: Basically, setting up the popup as a semi-Singleton instance.)

Leave a Reply