Android Surfaceview Hilos y fugas de memoria

Estoy creando un juego en Android, y me di cuenta de que el juego tiene una fuga de memoria. Iv logró aislar la fuga de memoria en una aplicación más pequeña para que pueda ver bien y tratar de trabajar, cómo arreglarlo.

La aplicación utiliza una vista de superficie para su vista y tiene un hilo adjunto a la misma para hacer todo el dibujo a la pantalla. La pérdida de memoria ocurre cuando inicio una nueva actividad y cierra la que estoy usando actualmente. Puedo ver esto cuando hago un volcado de memoria en mi aplicación de prueba, ya que todo lo que hace es abrir y cerrar una actividad (actividad a -> actividad b -> actividad a). Iv tipo de corrió de ideas en cuanto a cómo puedo solucionar esto como iv intentó anular todas mis referencias que creo a la vista (dentro del hilo), iv trató de eliminar la devolución de llamada de la superficie cuando destruyo la vista, y también Dentro de la actividad, no parece hacer ninguna diferencia.

MemoryLeakActivity.java

package memory.leak; import memory.leak.view.MemoryLeak; import android.app.Activity; import android.os.Bundle; public class MemoryLeakActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MemoryLeak(this)); } } 

MemoryLeakViewThread.java

 package memory.leak.thread; import memory.leak.view.MemoryLeak; import android.view.SurfaceHolder; import android.graphics.Canvas; public class MemoryLeakViewThread extends Thread { private MemoryLeak view; private boolean run =false; public MemoryLeakViewThread(MemoryLeak view) { this.view =view; } public void setRunning(boolean run) { this.run =run; } @Override public void run() { Canvas canvas =null; SurfaceHolder holder =this.view.getHolder(); while(this.run) { canvas =holder.lockCanvas(); if(canvas !=null) { this.view.onDraw(canvas); holder.unlockCanvasAndPost(canvas); } } holder =null; this.view =null; } } 

MemoryLeak.java

 package memory.leak.view; import memory.leak.TestActivity; import memory.leak.thread.MemoryLeakViewThread; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Canvas; import android.graphics.Color; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.GestureDetector.OnGestureListener; public class MemoryLeak extends SurfaceView implements SurfaceHolder.Callback, OnGestureListener { private GestureDetector gesture; private MemoryLeakViewThread vThread; private Context context; public MemoryLeak(Context context) { super(context); this.getHolder().addCallback(this); this.vThread =new MemoryLeakViewThread(this); this.gesture =new GestureDetector(this); this.context =context; } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} public void surfaceCreated(SurfaceHolder holder) { if(!this.vThread.isAlive()) { this.vThread =new MemoryLeakViewThread(this); this.vThread.setRunning(true); this.vThread.start(); } } public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; if(this.vThread.isAlive()) { this.vThread.setRunning(false); while(retry) { try { this.vThread.join(); retry =false; } catch(Exception ee) {} } } this.vThread =null; this.context =null; } public boolean onTouchEvent(MotionEvent event) { return this.gesture.onTouchEvent(event); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { } @Override public void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); } @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } @Override public void onLongPress(MotionEvent e) {} @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onShowPress(MotionEvent e) {} @Override public boolean onSingleTapUp(MotionEvent e) { Intent helpScreenIntent =new Intent(this.context, TestActivity.class); this.context.startActivity(helpScreenIntent); if (this.context instanceof Activity) ((Activity) this.context).finish(); return true; } } 

TestActivity.java

 package memory.leak; import memory.leak.view.Test; import android.app.Activity; import android.os.Bundle; public class TestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new Test(this)); } } 

TestViewThread.java

 package memory.leak.thread; import memory.leak.view.Test; import android.view.SurfaceHolder; import android.graphics.Canvas; public class TestViewThread extends Thread { private Test panel; private boolean run =false; public TestViewThread(Test panel) { this.panel =panel; } public void setRunning(boolean run) { this.run =run; } @Override public void run() { Canvas canvas =null; SurfaceHolder holder =this.panel.getHolder(); while(this.run) { canvas =holder.lockCanvas(); if(canvas !=null) { this.panel.onDraw(canvas); holder.unlockCanvasAndPost(canvas); } } holder =null; this.panel =null; } } 

Test.java

 package memory.leak.view; import memory.leak.MemoryLeakActivity; import memory.leak.thread.TestViewThread; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Canvas; import android.graphics.Color; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.GestureDetector.OnGestureListener; public class Test extends SurfaceView implements SurfaceHolder.Callback, OnGestureListener { private GestureDetector gesture; private TestViewThread vThread; private Context context; public Test(Context context) { super(context); this.getHolder().addCallback(this); this.vThread =new TestViewThread(this); this.gesture =new GestureDetector(this); this.context =context; } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} public void surfaceCreated(SurfaceHolder holder) { if(!this.vThread.isAlive()) { this.vThread =new TestViewThread(this); this.vThread.setRunning(true); this.vThread.start(); } } public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; if(this.vThread.isAlive()) { this.vThread.setRunning(false); while(retry) { try { this.vThread.join(); retry =false; } catch(Exception ee) {} } } this.vThread =null; this.context =null; } public boolean onTouchEvent(MotionEvent event) { return this.gesture.onTouchEvent(event); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { } @Override public void onDraw(Canvas canvas) { canvas.drawColor(Color.RED); } @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } @Override public void onLongPress(MotionEvent e) {} @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onShowPress(MotionEvent e) {} @Override public boolean onSingleTapUp(MotionEvent e) { Intent helpScreenIntent =new Intent(this.context, MemoryLeakActivity.class); this.context.startActivity(helpScreenIntent); if (this.context instanceof Activity) ((Activity) this.context).finish(); return true; } } 

–Edit– Hice cambios en la clase de vista a su surfaceDestroyed (SurfaceHolder titular) de modo que se establezca la vista de que el hilo tiene que null cuando el hilo se dice que se detiene. Los cambios que hice son

 public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; if(this.vThread.isAlive()) { this.vThread.setRunning(false); while(retry) { try { this.vThread.join(); retry =false; } catch(Exception ee) {} } this.vThread.setRunning(false, null); } this.vThread =null; this.context =null; this.gesture =null; } 

También necesita cambiar el método surfaceCreated (SurfaceHolder holder) para

 public void surfaceCreated(SurfaceHolder holder) { if(!this.vThread.isAlive()) { this.vThread =new MemoryLeakViewThread(); this.vThread.setRunning(true, this); this.vThread.start(); } } 

Entonces en la clase thread debemos cambiar lo siguiente

 public MemoryLeakViewThread() { } public void setRunning(boolean run) { this.run =run; } public void setRunning(boolean run, MemoryLeak view) { this.run =run; this.view =view; } 

Haciendo esto parecía de fijado el problema, el único problema ahora es el hilo parece permanecer en memoria, debido a la clase del hilo y al grupo del hilo. Pero estoy pensando que esto podría ser debido al depurador.

No debe crear nuevo Thread en el constructor cuando lo está creando en onSurfaceCreated. Compare su código con mi ejemplo: ¿Cómo puedo usar el marco de animación dentro del lienzo?

Como puede ver aquí:

http://developer.android.com/resources/articles/avoiding-memory-leaks.html

La forma más sencilla de iniciar una pérdida de memoria en Android es pasar al constructor de una vista toda la actividad en lugar del contexto de la aplicación. ¿Ha intentado cambiar esta línea:

 setContentView(new MemoryLeak(this)); 

En este:

 setContentView(new MemoryLeak(Context.getApplicationContext())); 

?

Espero eso ayude.

  • Android Vista vs SurfaceView vs GLSurfaceView para la aplicación de dibujo 2D con Zoomable interfaz de usuario
  • Vista previa de Android SurfaceView borrosa
  • Tome fotos sin previsualizar Android
  • Android: toma fotos sin vista previa
  • ¿Por qué onTouchEvent de SurfaceView llamado unos segundos retrasados?
  • Tomar una foto lo más rápido posible con la API de la cámara en Android
  • Android: hilo deteniéndose intermitentemente
  • SurfaceView y ANownWindow
  • Uso de surfaceView para capturar un video
  • Obtener información de GPU en Android sin SurfaceView
  • Uso de la API de la cámara android para mostrar la alimentación de la cámara
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.