Androidカスタムビュービットマップメモリリーク
-
11-10-2019 - |
質問
2つのビットマップを描く必要があるカスタムビューがあります。1つは背景であり、マップの画像を表し、もう1つはキャンバスの上/左の位置に描画されるピンです。
どちらの画像も描画されており、ビューを含むアクティビティのライブ中は同じままです。しばらくすると、私は
outofmemoryerror:ビットマップサイズはVM予算を超えています
これは、漏れがあり、ビットマップがゴミを集めないことを意味します。前にこの質問をしましたが、今では状況が少し変わりました。使用したいビットマップを設定するinitメソッドを作成しましたが、これはまだ良いアプローチではありません。エラーは後で表示されますが、それでもそこにあります。
これがコードです
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();
}
}
ビューを含むアクティビティを作成して、setmapbitmap()およびinit()を呼び出します。そこでは、どのビットマップがマップとして使用されるかを知っています。アクティビティの範囲で、私はビューの破壊()と呼びます。まだエラーが発生します。私はこれを読みました これ しかし、私は私のケースにそれを適応させる方法がわかりません
私は他のソリューションに対して開かれています。マップビットマップ(MAIアクティビティに含まれるレイアウトの高さに基づいて)を変更する必要があり、正しい場所に位置を描くことができることに注意してください。
解決
明らかにメモリリークがあります。方法を読んでください メモリリークを避けてください そして方法 メモリリークを見つけます.
これは、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();
}
}
他のヒント
あなたのコードで私をマークしたのは、あなたがすべてのビットマップを明らかにリサイクルしないことです。ここに役立つコードスニペットがいくつかあります。
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;
と:
Bitmap temp = BitmapFactory.decodeResource(context.getResources(), resource, opts);
Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true);
temp.recycle();