I recently discovered how easy it is to accidentally “leak” memory and resources in an Android application.
In this tutorial, I’ll illustrate a memory leak with a simple dialog box example, and then show you how to fix it.
Let’s start by creating a simple Android application that displays a dialog in its onCreate event:
[java]
package com.justinschultz.android;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
public class LeakedDialogActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setMessage("This dialog leaks!").setTitle("Leaky Dialog").setCancelable(false).setPositiveButton("Ok", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which) {}
});
AlertDialog alert = builder.create();
alert.show();
}
}
[/java]
If you’ve copied this correctly, the app should look like this:
While this application is running, take a look in LogCat. (In Eclipse, LogCat can be displayed via Window -> Show View -> LogCat.)
While the dialog is displayed, rotate the device (or the emulator by pressing CTRL+F11).
You should see a lot of bright red error text in LogCat that looks something like this:
Even though it looks like everything is working correctly on the device, LogCat displays this error message:
[java wraplines=”true”]
Activity com.justinschultz.android.LeakedDialogActivity has leaked
window com.android.internal.policy.impl.PhoneWindow$DecorView@40543ec0
that was originally added here
[/java]
So… what happened?
When the device rotates, the onPause and onStop Activity events are invoked. Then a new landscape Activity is created, and its onCreate method is invoked.
Since the dialog is displayed and has a reference to the Activity, it can’t be garbage collected, and subsequently is leaked. That is, you’ve created an object that can’t be garbage collected.
To fix this, let’s make the dialog an Activity member variable and override the onPause method to dismiss it:
[java]
AlertDialog _alert;
@Override
public void onPause() {
super.onPause();
if(_alert != null)
_alert.dismiss();
}
[/java]
This will dismiss the dialog each time the Activity is destroyed and recreated and the error will magically disappear from LogCat.
Here’s the source for this example.
Leave a Reply