2010-11-13 62 views
0

我正在製作具有2個元素的自定義視圖:包含像位圖一樣的位圖和像引腳一樣工作的小型資源圖像的背景,以指示地圖上的位置。在每個GPS位置改變我的觀點得到更新和引腳移動到新的位置。Android自定義視圖位圖大小超過虛擬機預算

首先,它炒菜很好,過了一段時間我得到這個錯誤:

ERROR/AndroidRuntime(416): java.lang.OutOfMemoryError: bitmap size exceeds VM budget

它是與重畫地圖的時候,我猜。也許你有任何想法來幫助我?

public class MyMapView extends View { 

private int xPos = 0; 
private int yPos = 0; 
private Bitmap trackMap; 

private Paint backgroundPaint; 
private Bitmap resizedBitmap; 

private Bitmap position; 
private Matrix positionMatrix; 
private Paint positionPaint; 
private int space=0; 

public MyMapView(Context context) { 
super(context); 
init(context, null); 
} 

public MyMapView(Context context, AttributeSet attrs) { 
super(context, attrs); 
init(context, attrs); 
} 

public MyMapView(Context context, AttributeSet attrs, int defStyle) { 
super(context, attrs, defStyle); 
init(context, attrs); 
} 

private void init(final Context context, AttributeSet attrs) { 
backgroundPaint = new Paint(); 
backgroundPaint.setFilterBitmap(true); 

position = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.position); 
positionMatrix = new Matrix(); 

positionPaint = new Paint(); 
positionPaint.setFilterBitmap(true); 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); 
} 

@Override 
protected void onDraw(Canvas canvas) { 

int width = getMeasuredWidth(); 
int height = getMeasuredHeight(); 

    if (trackMap!=null) 
    { 

    resizedBitmap = Bitmap.createScaledBitmap(trackMap, height, height, true); 



    space = (width - resizedBitmap.getWidth())/2; 
    canvas.drawBitmap(resizedBitmap, space, 0, backgroundPaint); 
    } 


    if (xPos != 0 && yPos !=0) 
    { 
     canvas.save(Canvas.MATRIX_SAVE_FLAG); 

     canvas.translate(xPos+space-position.getWidth()/2, yPos-position.getHeight()/2); 
     canvas.drawBitmap(position, positionMatrix, positionPaint); 

     canvas.restore(); 
    } 

} 

public void updatePosition(int xpos, int ypos, Bitmap trackImage) 
{ 
    xPos=xpos; 
    yPos=ypos; 
    trackMap = trackImage; 
    invalidate(); 
} 
} 

@Fedor:我已經試過這樣的事情:

if (trackMap!=null) 
    { 
    if (resizedBitmap != null) { 
    resizedBitmap.recycle(); 
    } 


    resizedBitmap = Bitmap.createScaledBitmap(trackMap, height, height, true); 



    space = (width - resizedBitmap.getWidth())/2; 
    canvas.drawBitmap(resizedBitmap, space, 0, backgroundPaint); 
    } 

    } 

但仍然是相同的。每次GPS檢測到位置發生變化時,我都會從活動中調用updatePosition(..),所以onDraw get的調用頻率很高。圖像地圖是400×400像素

11-13 20:29:42.121: ERROR/AndroidRuntime(213): Uncaught handler: thread main exiting due to uncaught exception 
11-13 20:29:42.150: ERROR/AndroidRuntime(213): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.graphics.Bitmap.nativeCreate(Native Method) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.graphics.Bitmap.createBitmap(Bitmap.java:468) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.graphics.Bitmap.createBitmap(Bitmap.java:435) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at com.vorienteering.customcontrols.MyMapView.onDraw(MyMapView.java:71) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.View.draw(View.java:6274) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.drawChild(ViewGroup.java:1526) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.drawChild(ViewGroup.java:1524) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.View.draw(View.java:6277) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.drawChild(ViewGroup.java:1526) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.View.draw(View.java:6277) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.drawChild(ViewGroup.java:1526) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.drawChild(ViewGroup.java:1524) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.View.draw(View.java:6277) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.widget.FrameLayout.draw(FrameLayout.java:352) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1883) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewRoot.draw(ViewRoot.java:1332) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewRoot.performTraversals(ViewRoot.java:1097) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.view.ViewRoot.handleMessage(ViewRoot.java:1613) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.os.Handler.dispatchMessage(Handler.java:99) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.os.Looper.loop(Looper.java:123) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at android.app.ActivityThread.main(ActivityThread.java:4203) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at java.lang.reflect.Method.invokeNative(Native Method) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at java.lang.reflect.Method.invoke(Method.java:521) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549) 
11-13 20:29:42.150: ERROR/AndroidRuntime(213):  at dalvik.system.NativeStart.main(Native Method) 

@Peter Knego我編輯如你的答案。它找到positionRef和其他一些人有問題。我更新了這樣的代碼:

@Override 
protected void onDraw(Canvas canvas) { 

    int width = getMeasuredWidth(); 
    int height = getMeasuredHeight(); 

    if (trackMapRef != null) { 

     Bitmap resizedBitmap = Bitmap.createScaledBitmap(trackMapRef.get(), width, height, true); 


     space = (width - resizedBitmap.getWidth())/2; 
     canvas.drawBitmap(resizedBitmap, space, 0, backgroundPaintRef.get()); 
    } 


    if (xPos != 0 && yPos != 0) { 
     canvas.save(Canvas.MATRIX_SAVE_FLAG); 

     positionRef = new WeakReference<Bitmap>(BitmapFactory.decodeResource(getContext().getResources(), R.drawable.position)); 
     positionMatrixRef = new WeakReference<Matrix>(new Matrix()); 
     Paint posPaint = new Paint(); 
     posPaint.setFilterBitmap(true); 
     positionPaintRef = new WeakReference<Paint>(posPaint); 

     canvas.translate(xPos + space - positionRef.get().getWidth()/2, yPos - positionRef.get().getHeight()/2); 
     canvas.drawBitmap(positionRef.get(), positionMatrixRef.get(), positionPaintRef.get()); 

     canvas.restore(); 
    } 

} 

現在它的工作時間稍長。加倍時間。但仍然給出了內存不足的錯誤。 非常感謝您的幫助。

我在想Fedor提到的,有沒有一種方法可以在創建時繪製地圖圖像,然後只更新onDraw的位置?這似乎是更方便的方式,因爲重繪地圖只使用資源,而且它一直都是一樣的。

謝謝大家的幫助。這是阻止我完成項目的唯一因素。

回答

1

你正在泄漏記憶。你有沒有嘗試過resizedBitmap.recycle()?

此外,爲什麼你總是重繪地圖?也許你可以將地圖作爲靜態圖像並重新繪製引腳?

+0

這就是我的想法,但我不知道如何不總是繪製地圖,因爲通常我只需要在創建視圖時繪製它。使用過程中地圖不會改變。 – Alin 2010-11-14 07:48:17

2

避免保留對Drawables(位圖)的引用 - 刪除類型位圖的類字段。

瞭解如何avoid memory leaks

被修改:

嘗試這種情況:

public class MyMapView extends View { 

    private int xPos = 0; 
    private int yPos = 0; 
    private WeakReference<Bitmap> trackMapRef; 

    private WeakReference<Paint> backgroundPaintRef; 

    private WeakReference<Bitmap> positionRef; 
    private WeakReference<Matrix> positionMatrixRef; 
    private WeakReference<Paint> positionPaintRef; 
    private int space = 0; 

    public MyMapView(Context context) { 
     super(context); 
     init(context, null); 
    } 

    public MyMapView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(context, attrs); 
    } 

    public MyMapView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     init(context, attrs); 
    } 

    private void init(final Context context, AttributeSet attrs) { 
     Paint paint = new Paint(); 
     paint.setFilterBitmap(true); 
     backgroundPaintRef = new WeakReference<Paint>(paint); 

     positionRef = new WeakReference<Bitmap>(BitmapFactory.decodeResource(getContext().getResources(), R.drawable.position)); 
     positionMatrixRef = new WeakReference<Matrix>(new Matrix()); 

     Paint posPaint = new Paint(); 
     posPaint.setFilterBitmap(true); 
     positionPaintRef = new WeakReference<Paint>(posPaint); 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 

     int width = getMeasuredWidth(); 
     int height = getMeasuredHeight(); 

     if (trackMapRef != null) { 

      Bitmap resizedBitmap = Bitmap.createScaledBitmap(trackMapRef.get(), width, height, true); 


      space = (width - resizedBitmap.getWidth())/2; 
      canvas.drawBitmap(resizedBitmap, space, 0, backgroundPaintRef.get()); 
     } 


     if (xPos != 0 && yPos != 0) { 
      canvas.save(Canvas.MATRIX_SAVE_FLAG); 

      canvas.translate(xPos + space - positionRef.get().getWidth()/2, yPos - positionRef.get().getHeight()/2); 
      canvas.drawBitmap(positionRef.get(), positionMatrixRef.get(), positionPaintRef.get()); 

      canvas.restore(); 
     } 

    } 

    public void updatePosition(int xpos, int ypos, Bitmap trackImage) { 
     xPos = xpos; 
     yPos = ypos; 
     trackMapRef = new WeakReference<Bitmap>(trackImage); 
     invalidate(); 
    } 
} 
+0

請您詳細說明一下嗎?我不明白你的意思是刪除typeBitmap的類字段。我需要在我的updatePosition中的位圖作爲參數,並且我在onDraw中使用該位圖。感謝您的幫助。 – Alin 2010-11-13 18:58:33

+0

編輯答案。 – 2010-11-13 20:15:48

+0

編輯了第一篇文章。它仍然不起作用。 – Alin 2010-11-15 18:33:10

0

使用decodeResource(RES,ID,選擇採用) 和OPTS使用以下代碼 BitmapFactory.Options bfOptions =新BitmapFactory.Options() ;

   bfOptions.inDither=false;      //Disable Dithering mode 

       bfOptions.inPurgeable=true;     //Tell to gc that whether it needs free memory, the Bitmap can be cleared 

       bfOptions.inInputShareable=true;    //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future 

       bfOptions.inTempStorage=new byte[32 * 1024]; 
相關問題