Java – Why does this leak when spinning?

Why does this leak when spinning?… here is a solution to the problem.

Why does this leak when spinning?

I ran into the following memory leak example

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();
    }
}

I don’t understand why it leaks when spinning. I know that a new activity will be created while the dialog is still on the screen (containing a reference to the old activity). Suppose you close the dialog box and rotate it again. Shouldn’t references to the oldest activities disappear, allowing memory to be reclaimed?

Solution

AlertDialogs (if used outside of fragments) should be instantiated via onCreateDialog()/showDialog() to avoid leaks.

This implementation is deprecated and should be replaced with DialogFragment, but will work for you:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

showDialog(YOUR_DIALOG_ID);
}

@Override
protected Dialog onCreateDialog(int id) {
    switch(id) {
    case YOUR_DIALOG_ID:
        return new AlertDialog.Builder(LeakedDialogActivity.this)
        .setIcon(android. R.drawable.ic_dialog_alert)
        .setMessage("This dialog leaks!")
        .setTitle("Leaky Dialog")
        .setCancelable(false)
        .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {}
        })
        .create();
    }
    return super.onCreateDialog(id);
}

Added

When you don’t create a dialog box in an onCreateDialog, it is essentially not attached to (or by) an Activity, so it is a lifecycle. When an Activity is destroyed or recreated, Dialog maintains a reference to it.

Theoretically, if you use setOwnerActivity() and close in onPause() (I believe), Dialog shouldn’t leak.

As far as leaks in general go, I’m not sure you need to worry too much about this issue. Dialog boxes are a special case.

Related Problems and Solutions