tengo - Evita las pérdidas de memoria en Android
mi celular dice memoria llena y esta vacia (4)
Acabo de leer una entrada de blog de Romain Guy sobre cómo evitar pérdidas de memoria en Android.
En el artículo da este ejemplo:
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
Romain dijo:
Este ejemplo es uno de los casos más simples de filtración del contexto.
Mi pregunta es, ¿cómo se modifica correctamente?
Al igual que esto?
TextView label = new TextView(Context.getApplicationContext());
He probado de ambas maneras y los resultados son los mismos. No puedo encontrar la diferencia. Y creo que this
es más correcto que el contexto de la aplicación. Debido a que this
es una referencia a la Activity
, es decir, el TextView
pertenece a esa Activity
.
¿Podría alguien darme una explicación para esto?
El problema real con ese código no es el contexto pasado para crear el sBackground estático Drawable, pero estático privado; El Drawable estático se crea con la Activity como contexto, por lo que en ESE caso, hay una referencia estática a un Drawable que hace referencia a la Activity, y es por eso que hay una fuga. Mientras exista esa referencia, la Actividad se mantendrá en la memoria, filtrando todas sus vistas.
Así que es el Drawable que debe crearse usando el contexto de la aplicación, no el TextView. Crear el TextView con "esto" está perfectamente bien.
edición: en realidad, eso podría no hacer una gran diferencia, el problema es que una vez que el dibujable se vincula a una vista, hay una referencia a la vista, que hace referencia a la actividad. Por lo tanto, debe "desenlazar" el dibujo cuando salga de la actividad.
La pérdida de memoria en ese código ocurre principalmente cuando giras tu pantalla (es decir, cambiando el estado de orientación), por lo que tu actividad se destruyó y se creó nuevamente para la nueva orientación. Hay muchas explicaciones sobre las fugas de memoria.
Puede ver uno de los videos de Google I / O 2011 sobre Gestión de la memoria here . En el video, también puede usar las herramientas de administración de memoria como el Analizador de memoria disponible para descargar here .
No estoy seguro de si Romain había actualizado su entrada de blog desde que la leíste, pero tiene bastante claro cómo evitar las fugas, incluso indicándote un ejemplo en el sistema operativo Android. Tenga en cuenta que he corregido el enlace roto en la entrada del blog de Romain a través de archive.org.
Este ejemplo es uno de los casos más simples de filtración del contexto y puede ver cómo lo resolvimos en el código fuente de la pantalla de inicio (busque el método unbindDrawables ()) configurando las devoluciones de llamada de los drawables almacenados en nulos cuando se destruye la actividad. . Curiosamente, hay casos en los que puedes crear una cadena de contextos filtrados, y son malos. Te hacen quedarse sin memoria bastante rápido.
Hay dos formas fáciles de evitar las fugas de memoria relacionadas con el contexto. La más obvia es evitar escapar del contexto fuera de su propio alcance. El ejemplo anterior mostró el caso de una referencia estática, pero las clases internas y su referencia implícita a la clase externa pueden ser igualmente peligrosas. La segunda solución es utilizar el contexto de la aplicación. Este contexto vivirá mientras su aplicación esté activa y no dependa del ciclo de vida de las actividades. Si planea mantener objetos de larga duración que necesitan un contexto, recuerde el objeto de la aplicación. Puede obtenerlo fácilmente llamando a Context.getApplicationContext () o Activity.getApplication ().
En resumen, para evitar pérdidas de memoria relacionadas con el contexto, recuerde lo siguiente:
- No mantenga referencias duraderas a una actividad de contexto (una referencia a una actividad debe tener el mismo ciclo de vida que la actividad en sí)
- Trate de usar la aplicación de contexto en lugar de una actividad de contexto
- Evite las clases internas no estáticas en una actividad si no controla su ciclo de vida, use una clase interna estática y haga una referencia débil a la actividad en su interior. La solución a este problema es usar una clase interna estática con una WeakReference a la clase externa, como se hace en ViewRoot y su clase interna W, por ejemplo
- Un recolector de basura no es un seguro contra las fugas de memoria
No sé si está teniendo problemas con esto en su aplicación, pero he creado una solución que soluciona todos los problemas de pérdida de memoria de Android con clases estándar de Android: http://code.google.com/p/android/issues/detail?id=8488#c51
public abstract class BetterActivity extends Activity
{
@Override
protected void onResume()
{
System.gc();
super.onResume();
}
@Override
protected void onPause()
{
super.onPause();
System.gc();
}
@Override
public void setContentView(int layoutResID)
{
ViewGroup mainView = (ViewGroup)
LayoutInflater.from(this).inflate(layoutResID, null);
setContentView(mainView);
}
@Override
public void setContentView(View view)
{
super.setContentView(view);
m_contentView = (ViewGroup)view;
}
@Override
public void setContentView(View view, LayoutParams params)
{
super.setContentView(view, params);
m_contentView = (ViewGroup)view;
}
@Override
protected void onDestroy()
{
super.onDestroy();
// Fixes android memory issue 8488 :
// http://code.google.com/p/android/issues/detail?id=8488
nullViewDrawablesRecursive(m_contentView);
m_contentView = null;
System.gc();
}
private void nullViewDrawablesRecursive(View view)
{
if(view != null)
{
try
{
ViewGroup viewGroup = (ViewGroup)view;
int childCount = viewGroup.getChildCount();
for(int index = 0; index < childCount; index++)
{
View child = viewGroup.getChildAt(index);
nullViewDrawablesRecursive(child);
}
}
catch(Exception e)
{
}
nullViewDrawable(view);
}
}
private void nullViewDrawable(View view)
{
try
{
view.setBackgroundDrawable(null);
}
catch(Exception e)
{
}
try
{
ImageView imageView = (ImageView)view;
imageView.setImageDrawable(null);
imageView.setBackgroundDrawable(null);
}
catch(Exception e)
{
}
}
// The top level content view.
private ViewGroup m_contentView = null;
}