tutorial studio how drawtextonpath customview custom create control content android out-of-memory ondraw custom-view

studio - drawtextonpath android



Fuga de memoria bitmap de la vista personalizada de Android (2)

Tengo una vista personalizada en la que necesito dibujar dos mapas de bits, uno es un fondo, que representa la imagen de un mapa y el otro es un pin que se dibujará en la posición superior / izquierda en el lienzo.

Ambas imágenes se dibujan en Dibujo y permanecen iguales durante la vida de la actividad que contiene la vista. Después de un tiempo me sale un

OutOfMemoryError: el tamaño del mapa de bits supera el presupuesto de la máquina virtual

Esto significa que tengo una fuga y los mapas de bits no se recolectan basura. Hice esta pregunta antes, pero ahora la situación cambió un poco. Hice un método de inicio en el que establezco los mapas de bits que quiero usar, pero todavía no es un buen enfoque, el error aparece más tarde, pero sigue ahí.

Aquí está el código

public class MyMapView extends View { private int xPos = 0; private int yPos = 0; private int space = 0; private Bitmap resizedBitmap; private Bitmap position; private Bitmap mapBitmap; public void setMapBitmap(Bitmap value) { this.mapBitmap = value; } public MyMapView(Context context) { super(context); } public MyMapView(Context context, AttributeSet attrs) { super(context, attrs); } public MyMapView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void init(final Context context) { Paint paint = new Paint(); paint.setFilterBitmap(true); int width = getMeasuredWidth(); int height = getMeasuredHeight(); resizedBitmap = Bitmap.createScaledBitmap(mapBitmap, height, height, true); position = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.position); space = (width - resizedBitmap.getWidth()) / 2; } public void destroy() { resizedBitmap.recycle(); resizedBitmap=null; position.recycle(); position=null; mapBitmap.recycle(); mapBitmap=null; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); } @Override protected void onDraw(Canvas canvas) { if (mapBitmap != null) { canvas.drawBitmap(resizedBitmap, space, 0, null); } if (xPos != 0 && yPos != 0) { canvas.translate(xPos + space - position.getWidth() / 2, yPos - position.getHeight() / 2); canvas.drawBitmap(position, new Matrix(), new Paint()); } } public void updatePosition(int xpos, int ypos) { xPos = xpos; yPos = ypos; invalidate(); } }

Llamo a setMapBitmap () y init () en onCreate de la actividad que contiene la vista. Allí sé qué mapa de bits se utilizará como mapa. onPause de la actividad que llamo destroy () de la vista. Todavía tengo errores. He leído esto, pero no sé cómo adaptarlo a mi caso

Estoy abierto a cualquier otra solución. Tenga en cuenta que necesito cambiar el tamaño del mapa de bits del mapa (en función de la altura del diseño que lo contiene en la actividad principal) y poder dibujar la posición en el lugar correcto.


Algo que me marcó en tu código es que aparentemente no reciclas todos tus mapas de bits. Aquí hay un par de fragmentos de código que podrían ayudar:

bmp = getBitmapFromRessourceID(R.drawable.menu); ratio = (float)this.height/(float)bmp.getScaledHeight(canvas); temp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth()*ratio), (int) (bmp.getHeight()*ratio-10), false); bmp.recycle(); bmp = temp;

y:

Bitmap temp = BitmapFactory.decodeResource(context.getResources(), resource, opts); Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true); temp.recycle();


Obviamente tienes una pérdida de memoria. Lea cómo evitar las pérdidas de memoria y cómo encontrarlas .

Aquí está un código refactorizado para usar WeakReference:

public class MyMapView extends View { private int xPos = 0; private int yPos = 0; private int space = 0; private WeakReference<Bitmap> resizedBitmap; private WeakReference<Bitmap> position; private WeakReference<Bitmap> mapBitmap; public void setMapBitmap(Bitmap value) { this.mapBitmap = new WeakReference<Bitmap>(value); } public MyMapView(Context context) { super(context); } public MyMapView(Context context, AttributeSet attrs) { super(context, attrs); } public MyMapView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void init(Bitmap mapBitmap) { Paint paint = new Paint(); paint.setFilterBitmap(true); int width = getMeasuredWidth(); int height = getMeasuredHeight(); resizedBitmap = new WeakReference<Bitmap>(Bitmap.createScaledBitmap( mapBitmap, width, height, true)); position = new WeakReference(BitmapFactory.decodeResource( getContext().getResources(), R.drawable.position)); space = (width - resizedBitmap.get().getWidth()) / 2; } // public void destroy() { // resizedBitmap.recycle(); // resizedBitmap = null; // position.recycle(); // position = null; // mapBitmap.recycle(); // mapBitmap = null; // } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); } @Override protected void onDraw(Canvas canvas) { if (mapBitmap != null) { canvas.drawBitmap(resizedBitmap.get(), space, 0, null); } if (xPos != 0 && yPos != 0) { canvas.translate(xPos + space - position.get().getWidth() / 2, yPos - position.get().getHeight() / 2); canvas.drawBitmap(position.get(), new Matrix(), null); } } public void updatePosition(int xpos, int ypos) { xPos = xpos; yPos = ypos; invalidate(); } }