Android benutzerdefinierte Ansicht Bitmap Speicherleck
-
11-10-2019 - |
Frage
Ich habe eine benutzerdefinierte Ansicht habe, in dem ich brauche zwei Bitmaps zu ziehen, ist ein Hintergrund, was das Bild einer Karte und man ist ein Stift, der auf der Oberseite / linke Position in Leinwand gezogen werden.
Die beiden Bilder sind gezeichnet OnDraw und gleich bleiben während des Live von der Tätigkeit, die die Ansicht enthält. Nach einer Weile ich ein
erhaltenOutOfMemoryError: Bitmap-Größe überschreitet VM Budget
Das bedeutet, dass ich ein Leck haben und die Bitmaps nicht bekommen Müll gesammelt. Ich habe diese Frage vor, aber jetzt ist die Situation ein wenig geändert. Ich habe eine init-Methode, wo ich die Bitmaps gesetzt ich verwenden möchte, aber das ist noch kein guter Ansatz, erscheint der Fehler später, aber immer noch da.
Hier ist der Code
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();
}
}
Ich nenne die setMapBitmap () und init () auf onCreate der Aktivität, die die Ansicht enthält. Dort weiß ich, was Bitmap wird als Karte verwendet werden. onPause der Aktivität nenne ich die destroy () der Ansicht. Ich bekomme immer noch Fehler. Ich habe diese Zeilen lesen href="http://mobi-solutions.blogspot.com/2010/08/how-to-if-you-want-to-create-and.html"> aber ich weiß nicht, wie es auf meinem Fall anpassen
Ich bin offen für jede andere Lösung. Bitte beachten Sie, dass ich die Karte Bitmap, um die Größe (bezogen auf der Höhe des Layouts, die es in mai Aktivität enthält) und noch in der Lage sein, die Position auf richtige Stelle zu ziehen.
Lösung
Sie haben offensichtlich ein Speicherleck. Lesen Sie, wie Sie vermeiden Speicherlecks und wie finden Speicherlecks .
Hier ist ein Code zur Verwendung WeakReference Refactoring:
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();
}
}
Andere Tipps
Etwas, das im Code markiert mich ist, dass Sie nicht alle Ihre Bitmaps scheinbar recyceln. Hier sind ein paar Code-Schnipsel, die helfen könnten:
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;
und
Bitmap temp = BitmapFactory.decodeResource(context.getResources(), resource, opts);
Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true);
temp.recycle();