Este articulo presente porqué Android TextView
esta responsable de una fuga de memoria cuando necesita de actualizar texto con alta frecuencia, y como hacer para evitar lo.Atención: comparto mi experiencia de debutante en Java sobre Android quien hubiera querido leer un articulo así antes. Es posible que paso al lado de algo.
problema: EL importante creación de objetos
Exhibo todas las 50ms las nuevas valores de los sensores: acelerómetro, giroscopio, y otros sensores qué pueden ser resultados directos del hardware o de la fusión de otros sensores. Ahí está lo que pasa al nivel de la memoria :

Sin tener cuenta de los pequeñitos mili-segundos de pausas impuestas por la liberación de la memoria, el garbage collector no se pretende a ser tan solicitando. Después qué limpié todo mi código de las construcciones de objetos (especialmente el objeto String
) de la función llamada, me he interesado a TextView
, e hice un análisis de la memoria:
Cada llamada a setText()
conlleva a la creación de un nuevo StaticLayout
, y evalúa exactamente las dimensiones del layout dependiente al su contenido. Excepto que cada creación de StaticLayout
conlleva a la creación de muchos objetos en memoria.
En mi caso, setText()
esta ademas demasiado usado considerando la decena de layouts qué tengo que actualizar constantemente. Desgraciadamente, reducir todo el contenido a un layout solo no cambiara nada, en alta frecuencia la sola creación de un objeto StaticLayout
consume ya bastante de memoria. Hay que abstenerse al máximo la creación de objetos.
UNA SOLUCIÓN : Dejar TextView
Para evitar eso, luego creé un nuevo tipo de View
que actúa como un layout especializado, de dimensiones conocidas (porqué el contenido toma siempre el mismo tamaño de altura y casi el mismo tamaño de longitud) al cual modifico su evento onDraw()
qué es el evento llamado para después escribir texto manualmente con Canvas.drawText()
, con el objetivo de pasar a través del comportamiento básico de un TextView
.
public class SensorView extends View { ... private final char[] buffer = new char[BUFFER_SIZE]; private final Paint paint = new Paint(); public SensorView(Context context) { super(context); this.initPaint(); } public SensorView(Context context, AttributeSet attrs) { super(context, attrs); // Get back some values from xml data this.padding = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "padding", this.padding); this.textSize = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "padding", this.textSize); this.initPaint(); } public void initPaint() { // Setting the paint this.padding = getPixels(TypedValue.COMPLEX_UNIT_DIP, this.padding); this.textSize = getPixels(TypedValue.COMPLEX_UNIT_SP, this.textSize); this.paint.setAntiAlias(true); this.paint.setColor(Color.DKGRAY); this.paint.setTextSize(this.textSize); } @Override public void onDraw(Canvas canvas) { int start = 0, line = 0; // Display multi-lines content for (int i = 0; i < BUFFER_SIZE; i++) { if (buffer[i] == '\n' || buffer[i] == '\0') { canvas.drawText(buffer, start, i-start, this.padding, line++ * this.textSize * LINE_HEIGHT + this.padding, paint); start = i+1; } } } public void setText(StringBuilder source) { source.getChars(0, source.length(), buffer, 0); } private int getPixels(int unit, float size) { DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); return (int)TypedValue.applyDimension(unit, size, metrics); } }
Para cada modificación, llamo SensorView.postInvalidate()
qué invalida la View
y con consecuencia llama una otra vez onDraw()
. Por supuesto, no aprovecho de las optimizaciones de rendimiento relacionadas con TextView
, pero de todas formas mi texto siempre no sea el mismo et por eso no cumpliera cualquier sistema de caché. Ahí esta el nuevo resultado al nivel de la memoria:

¡ Problema solventado !