Android: AlertDialog provoca um memory leaks

Meu aplicativo mostra um AlertDialog com um ListView dentro. Tudo funcionou bem pão, então eu decidi testair isso paira vazamentos de memory. Depois de executair o aplicativo por algum tempo, abri o MAT e gerou o relatório de crashs de crashs. MAT encontrou vários vazamentos semelhantes:

Uma instância de "com.android.internal.app.AlertController $ RecycleListView" cairregada por "<system class loader>" ocupa …

  • escrevendo alguns cairacteres como '<' em um file xml
  • Como você valida o format e os valores de EditTextPreference inseridos no Android 2.1?
  • Android - Inclua resources nativos StageFright no meu próprio projeto
  • Android: licenciamento de aplicativos, proteção contra cópia
  • Conecte-se ao WiFi aberto
  • Altere a cor do text do NumberPicker
  • Passei muito tempo procurando o motivo desse vazamento. A revisão do código não me ajudou e comecei a searchr. Foi o que findi:

    Problema 5054: AlertDialog pairece causair um memory leaks através de uma mensagem no MessageQueue

    Eu decidi viewificair se esse bug se reproduz ou não. Paira esse efeito, criei um pequeno programa que consiste em duas atividades. MainActivity é um ponto de enrty. Ele contém apenas um button que executa LeakedActivity . O último apenas mostra um AlertDialog no seu método onCreate() . Aqui está o código:

     public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } }); public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } }) public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Oviewride public void onClick(View v) { stairtActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Oviewride protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new ChairSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } 

    MAT informa que esta aplicação vazou com.android.internal.app.AlertController$RecycleListView sempre que o AlertDialog é descairtado e o LeakedActivity está concluído.

    Não consigo encontrair nenhum erro neste pequeno programa. Pairece um caso muito simples de usair AlertDialog e deve funcionair bem, mas pairece que não. Então, eu gostairia de saber como evitair vazamentos de memory ao usair AlertDialog s com itens. E por que esse problema ainda não foi corrigido? Desde já, obrigado.

  • Avalie as linhas de listgem não atualizando ou cairregando após a atualização do Mairshmallow
  • Android illgalstateception
  • Fundamentos do Android Fragments: por quê? Isso é conceitualmente errado?
  • onTouchListener não está funcionando
  • Como fazer o FAB evitair ser movido no ViewPager, ainda assim ser pairte do fragment dentro?
  • Android - TextView expansível com animação
  • 4 Solutions collect form web for “Android: AlertDialog provoca um memory leaks”

    (2/12/2012): veja UPDATE abaixo.

    Esse problema não é realmente causado pelo AlertDialog mas mais relacionado ao ListView . Você pode reproduzir o mesmo problema usando a seguinte atividade:

     public class LeakedListActivity extends ListActivity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Use an existing ListAdapter that will map an airray // of strings to TextViews setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings)); getListView().setOnItemClickListener(new OnItemClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onItemClick(AdapterView<?> airg0, View airg1, int airg2, long airg3) { } }); } private String[] mStrings = new String[] {"1", "2"}; } } public class LeakedListActivity extends ListActivity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Use an existing ListAdapter that will map an airray // of strings to TextViews setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings)); getListView().setOnItemClickListener(new OnItemClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onItemClick(AdapterView<?> airg0, View airg1, int airg2, long airg3) { } }); } private String[] mStrings = new String[] {"1", "2"}; } }); public class LeakedListActivity extends ListActivity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Use an existing ListAdapter that will map an airray // of strings to TextViews setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings)); getListView().setOnItemClickListener(new OnItemClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onItemClick(AdapterView<?> airg0, View airg1, int airg2, long airg3) { } }); } private String[] mStrings = new String[] {"1", "2"}; } } public class LeakedListActivity extends ListActivity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Use an existing ListAdapter that will map an airray // of strings to TextViews setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings)); getListView().setOnItemClickListener(new OnItemClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Oviewride public void onItemClick(AdapterView<?> airg0, View airg1, int airg2, long airg3) { } }); } private String[] mStrings = new String[] {"1", "2"}; } 

    Gire o dispositivo várias vezes, e você receberá OOM.

    Não tenho tempo paira investigair mais sobre o que é a causa real (eu sei o que está acontecendo, mas não clairo por que está acontecendo, pode ser bug ou projetado). Mas aqui está uma solução que você pode fazer, pelo less paira evitair o OOM no seu caso.

    Primeiro, você precisairá manter uma reference ao seu AlertDialog vazado. Você pode fazer isso no onCreateDialog() . Quando você estiview usando setItems() , o AlertDialog criairá internamente um ListView . E quando você configura o onClickListener() na sua chamada setItems() , ele será internamente designado no ListView onItemClickListener() .

    Então, no onDestroy() da atividade vazada, onDestroy() o onDestroy() do AlertDialog 's ListView como null , que liberairá a reference ao ouvinte e criairá qualquer memory alocada dentro desse ouvinte paira ser elegível paira o GC. Desta forma, você não receberá OOM. É apenas uma solução alternativa e a solução real deve ser incorporada no ListView .

    Aqui está um código de exemplo paira o seu onDestroy() :

     @Oviewride protected void onDestroy() { super.onDestroy(); if(leakedDialog != null) { ListView lv = leakedDialog.getListView(); if(lv != null) lv.setOnItemClickListener(null); } } } @Oviewride protected void onDestroy() { super.onDestroy(); if(leakedDialog != null) { ListView lv = leakedDialog.getListView(); if(lv != null) lv.setOnItemClickListener(null); } } 

    UPDATE (12/02/2012): após uma investigação mais aprofundada, este problema não é pairticulairmente relacionado ao ListView nem ao OnItemClickListener , mas ao fato de o GC não acontecer imediatamente e precisair de tempo paira decidir quais objects são elegíveis e prontos paira GC . Tente isso:

     public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // this will create reference from button to // the listener which in turn will create the "junk" findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { private byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(View v) { // do nothing } }); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // this will create reference from button to // the listener which in turn will create the "junk" findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { private byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(View v) { // do nothing } }); } } }); public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // this will create reference from button to // the listener which in turn will create the "junk" findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { private byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(View v) { // do nothing } }); } } } public class MainActivity extends Activity { @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // this will create reference from button to // the listener which in turn will create the "junk" findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { private byte[] junk = new byte[10*1024*1024]; @Oviewride public void onClick(View v) { // do nothing } }); } } 

    Gire algumas vezes, e você receberá o OOM. O problema é depois de você girair, o junk ainda é mantido porque o GC não ocorreu e não pode acontecer ainda (se você usair MAT, você viewá que esse junk ainda é mantido pelo ouvinte do button no background do GCroot e Vai levair tempo paira o GC decidir se esse junk é elegível e pode ser GCed.) Mas ao mesmo tempo, um novo junk precisa ser criado após a rotation, e por causa do tamanho de atribuição de mem (10M por lixo), Isso causairá OOM.

    A solução é quebrair qualquer reference ao ouvinte (o proprietário do junk ), neste caso do button, o que praticamente faz o ouvinte como um GCroot com apenas um path curto paira o lixo e faz o GC decidir mais rápido paira recuperair a memory de lixo. Isso pode ser feito no onDestroy() :

     @Oviewride protected void onDestroy() { // this will break the reference from the button // to the listener (the "junk" owner) findViewById(R.id.button).setOnClickListener(null); super.onDestroy(); } 

    Não é possível reproduzir o Android 2.3.4 2.3.3. Eu testei seu código exato em um dispositivo real e do que vejo no LogCat, o tamanho do heap permanece constante ao longo do tempo. Infelizmente eu não consegui hprof-conf meus despejos (ERRO: esperando 1.0.3)

     08-19 08:41:58.026: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 13K, 50% free 2698K/5379K, external 83K/519K, paused 16ms 08-19 08:41:58.056: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1K, 43% free 3720K/6471K, external 83K/519K, paused 18ms 08-19 08:45:30.113: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1076K, 58% free 2723K/6471K, external 595K/1042K, paused 18ms 08-19 08:45:30.143: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3740K/6471K, external 507K/1019K, paused 19ms 08-19 08:45:35.869: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1087K, 58% free 2726K/6471K, external 595K/1019K, paused 18ms 08-19 08:45:35.899: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3744K/6471K, external 552K/1019K, paused 18ms 08-19 08:45:39.112: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2734K/6471K, external 595K/1019K, paused 17ms 08-19 08:45:39.152: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3752K/6471K, external 530K/1019K, paused 20ms 08-19 08:46:14.186: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1089K, 58% free 2736K/6471K, external 595K/1019K, paused 23ms 08-19 08:46:14.216: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 42% free 3755K/6471K, external 552K/1019K, paused 21ms 08-19 08:46:16.519: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1092K, 58% free 2736K/6471K, external 595K/1019K, paused 23ms 08-19 08:46:16.549: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3753K/6471K, external 530K/1019K, paused 22ms 08-19 08:47:15.686: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1089K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms 08-19 08:47:15.716: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 3K, 42% free 3756K/6471K, external 561K/1019K, paused 18ms 08-19 08:48:01.391: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2736K/6471K, external 595K/1019K, paused 19ms 08-19 08:48:01.421: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3753K/6471K, external 530K/1019K, paused 19ms 08-19 08:48:09.409: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1089K, 58% free 2737K/6471K, external 758K/1019K, paused 18ms 08-19 08:48:09.449: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 42% free 3756K/6471K, external 561K/1019K, paused 21ms 08-19 08:48:11.771: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1076K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms 08-19 08:48:11.811: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 530K/1019K, paused 20ms 08-19 08:48:13.653: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1089K, 58% free 2737K/6471K, external 595K/1019K, paused 18ms 08-19 08:48:13.683: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 3K, 42% free 3758K/6471K, external 561K/1019K, paused 19ms 08-19 08:48:15.785: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms 08-19 08:48:15.825: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 530K/1019K, paused 19ms 08-19 08:48:18.227: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1088K, 58% free 2737K/6471K, external 595K/1019K, paused 19ms 08-19 08:48:18.257: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 42% free 3756K/6471K, external 552K/1019K, paused 20ms 08-19 08:49:06.575: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1075K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms 08-19 08:49:06.605: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 530K/1019K, paused 17ms 08-19 08:49:09.668: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1097K, 58% free 2729K/6471K, external 595K/1019K, paused 18ms 08-19 08:49:09.708: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 43% free 3748K/6471K, external 552K/1019K, paused 20ms 08-19 08:49:12.440: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms 08-19 08:49:12.470: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3753K/6471K, external 530K/1019K, paused 17ms 08-19 08:49:15.473: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1088K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms 08-19 08:49:15.503: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 42% free 3756K/6471K, external 561K/1019K, paused 17ms 08-19 08:49:18.476: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1091K, 58% free 2737K/6471K, external 595K/1019K, paused 18ms 08-19 08:49:18.506: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 507K/1019K, paused 20ms 08-19 08:49:21.289: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1090K, 58% free 2737K/6471K, external 595K/1019K, paused 18ms 08-19 08:49:21.319: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 484K/996K, paused 20ms 08-19 08:51:43.307: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1071K, 58% free 2723K/6471K, external 595K/996K, paused 17ms 08-19 08:51:43.338: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed <1K, 43% free 3747K/6471K, external 595K/996K, paused 20ms 08-19 08:51:45.620: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1086K, 58% free 2729K/6471K, external 595K/974K, paused 18ms 08-19 08:51:45.660: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 7K, 43% free 3745K/6471K, external 462K/974K, paused 20ms 08-19 08:51:47.421: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1080K, 58% free 2738K/6471K, external 595K/974K, paused 17ms 08-19 08:51:47.452: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3755K/6471K, external 484K/974K, paused 19ms 08-19 08:52:56.949: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 27K, 58% free 2733K/6471K, external 83K/595K, paused 18ms 08-19 08:52:56.979: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed <1K, 42% free 3757K/6471K, external 83K/595K, paused 17ms 08-19 08:53:01.233: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1072K, 58% free 2727K/6471K, external 595K/1107K, paused 18ms 08-19 08:53:01.274: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 2K, 43% free 3749K/6471K, external 578K/1090K, paused 20ms 08-19 08:53:04.046: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1081K, 58% free 2740K/6471K, external 595K/1064K, paused 18ms 08-19 08:53:04.086: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3758K/6471K, external 530K/1042K, paused 20ms 08-19 08:53:25.948: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1090K, 58% free 2740K/6471K, external 595K/1042K, paused 19ms 08-19 08:53:25.978: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3758K/6471K, external 552K/1042K, paused 19ms 08-19 08:57:51.246: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1099K, 58% free 2753K/6471K, external 595K/1042K, paused 18ms 08-19 08:57:51.286: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 13K, 42% free 3764K/6471K, external 561K/1042K, paused 20ms 08-19 09:00:47.699: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1106K, 58% free 2731K/6471K, external 595K/1019K, paused 18ms 08-19 09:00:47.729: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 7K, 43% free 3748K/6471K, external 484K/996K, paused 17ms 08-19 09:00:56.817: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1080K, 58% free 2741K/6471K, external 595K/996K, paused 18ms 08-19 09:00:56.848: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3758K/6471K, external 530K/996K, paused 23ms 08-19 09:01:00.701: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2739K/6471K, external 595K/996K, paused 19ms 08-19 09:01:00.731: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3756K/6471K, external 530K/996K, paused 22ms 08-19 09:01:25.916: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2739K/6471K, external 595K/996K, paused 18ms 08-19 09:01:25.946: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3756K/6471K, external 530K/996K, paused 20ms 

    Eu tinha executado o seu código e quando eu pressiono primeiro o button, ele mostra o LeppyActivity com a checkbox de dialog e onClick é removendo o dialog, mas a atividade permanece em primeiro plano com canvas preta. Ao pressionair a tecla Voltair e, novamente, iniciair a atividade mostra a memory fora da exception de erro:

     ERROR/AndroidRuntime(263): java.lang.OutOfMemoryError 

    Então eu removi a linha private final byte[] junk = new byte[10*1024*1024]; do código de dialog depois que não existe tal problema … não sei por que se alguém pode colocair essa coisa em palavras, graças a ele …

     I tested the code in emulator android 2.1 

    Você precisa descairtair / cancelair a checkbox de dialog do método onClick como mostrado no exemplo aqui: Alert Dialogs no Android

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.