Can someone please explain me why this leaks?


Ask by : jnb November 04, 2012 23:24

Hey guys I'm new to Android development and I came across 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 on a rotation. I understand, a new Activity is created while the dialog is still on screen (containing a reference to the old activity). Suppose you close the dialog and rotate again. Shouldn't the reference to the oldest activity be gone, thus allowing the memory to be reclaimed?

View original question

Answer by : Paul BurkeNovember 04, 2012 23:24

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

This implementation is deprecated and should be replaced by a 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 in onCreateDialog its essentially not attached to (or owned by) the Activity, and therefore, it's lifecycle. When the Activity is destroyed or recreated, the Dialog maintains a reference to it.

In theory, the Dialog should not leak if you use setOwnerActivity() and dismiss in onPause() (I believe).

I'm not sure you have to worry much about this gotcha as far as general leaks go. Dialogs are kind of a special case.

View original answer