OutOfMemory错误:创建位图时位图超出VM预算

时间:2012-10-15 11:45:14

标签: android android-layout

我在这里使用MyView进行绘画。有时当我打开活动时,我得到一个OutOfMemory异常位图大小超过MyView onSizeChanged()中的VM预算。请问有人对我有什么建议吗?

这是我的代码:

private Paint mPaint; 
private Bitmap mBitmap;
private Canvas canvas;
public class MyView extends View
{
    private Path mPath;
    private Paint mBitmapPaint;

    public MyView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
         mPath = new Path();
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);            
        canvas = new Canvas(mBitmap);  
        super.onSizeChanged(w, h, oldw, oldh);
    }

    public void clear(){
        mBitmap = Bitmap.createBitmap(480, 480, Bitmap.Config.ARGB_8888);
        mPath = new Path();
        invalidate();
    }

    public void destroy() {
        if (mBitmap != null) {
            mBitmap.recycle();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(action)
        {
            invalidate();
        }

        int swidth=(int)(6*(screenWidth/1024));
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        //mPaint.setColor(0xFFFF0000);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(swidth);

        int swidth1=(int)(3*(screenWidth/1024));
        Paint painto = new Paint();
        painto.setAntiAlias(true);
        painto.setColor(getResources().getColor(R.color.magnata));
        painto.setStrokeWidth(swidth1);
        painto.setStyle(Paint.Style.FILL);

        xstart=(int)(15*(screenWidth/1024));
        xend=(int)(1010*(screenWidth/1024));
        ystart=(int)(90*(screenHeight/600));
        y1end=(int)(550*(screenHeight/600));

        canvas.drawLine(xstart, ystart, xend, ystart, painto);  
        canvas.drawLine(xstart, ystart, xstart, y1end, painto);
        canvas.drawLine(xstart, y1end, xend, y1end, painto);
        canvas.drawLine(xend, ystart, xend, y1end, painto);

        Paint p1=new Paint();

        p1.setColor(Color.BLACK);

        p1.setAntiAlias(true);

        Paint p2=new Paint();
        p2.setColor(getResources().getColor(R.color.bcolor));
        p2.setAntiAlias(true);

        float swidth3=(int)(120*(screenWidth/1024));

        float swidth4=(int)(4*(screenWidth/1024));
        p1.setTextSize(swidth3);
        p2.setTextSize(swidth3);

        Paint p3=new Paint();
        p3.setColor(Color.BLACK);
        p3.setStrokeWidth(swidth4);
        p3.setAntiAlias(true);
        p3.setStyle(Paint.Style.FILL);

        Typeface font = Typeface.createFromAsset(getAssets(), "font/KINDTRG.TTF"); 
        Typeface font2=Typeface.createFromAsset(getAssets(), "font/KINDB.TTF");
        p1.setTypeface(font);            
        p2.setTypeface(font);

        int xline1=(int)(15*(screenWidth/1024));

        int xline2=(int)(500*(screenWidth/1024));
        int yline1=(int)(5*(screenHeight/600));
        int yline2=(int)(85*(screenHeight/600));

        canvas.drawLine(xline1, yline1, xline2, yline1, p3);
        canvas.drawLine(xline1, yline2, xline2, yline2, p3);


        float width11=(int)(5*(screenWidth/1024));


        float width22=(int)(20*(screenWidth/1024));
        Paint paint9=new Paint();
        paint9.setStrokeWidth(width11);
        paint9.setColor(getResources().getColor(R.color.gray));
        paint9.setAntiAlias(true);
        DashPathEffect dashPath = new DashPathEffect(new float[]{width22,width22}, (float) 5.5);

        paint9.setPathEffect(dashPath);
        paint9.setStyle(Paint.Style.STROKE);

        float width121=(int)(2*(screenWidth/1024));
        Paint paint2=new Paint();
        paint2.setStrokeWidth(width121);
        paint2.setAntiAlias(true);
        paint2.setColor(Color.BLACK);
        paint2.setTextSize(15);
        paint2.setStyle(Style.STROKE);

        float width131=(int)(6*(screenWidth/1024));
        float textsize22=(int)(17*(screenWidth/1024));
        Paint paint1 = new Paint();

        paint1.setStyle(Paint.Style.FILL);
        paint1.setStrokeWidth(width131);
        paint1.setTypeface(font2);
        paint1.setAntiAlias(true);
        paint1.setColor(Color.BLACK);
        paint1.setTextSize(textsize22);

        int xtextl=(int)(65*(screenWidth/1024));
        int ytext1=(int)(107*(screenHeight/600));

        canvas.drawText("Say  the  words  that  start  with  the  short   a   sound .", xtextl, ytext1, paint1);


        int ytext2=(int)(228*(screenHeight/600));
        int ytext3=(int)(340*(screenHeight/600));
        int ytext4=(int)(359*(screenHeight/600));

        canvas.drawText("Circle  the  pictures  that  start  with  the  short   a   sound.", xtextl, ytext2, paint1);
        canvas.drawText("Say the name of each picture to help you determine the beginning sound.", xtextl,ytext3,paint1);
        canvas.drawText("  Press the tennis ball with the correct answer to spell the word.", xtextl, ytext4,paint1);


        Paint p=new Paint();
        int xcir1=(int)(65*(screenWidth/1024));
        int xcir2=(int)(1010*(screenWidth/1024));
        int xcir3=(int)(10*(screenWidth/1024));

        float rad=(int)(2*(screenWidth/1024));
        int ycir1=(int)(212*(screenHeight/600));
        int ycir2=(int)(323*(screenHeight/600));
        p.setColor(getResources().getColor(R.color.magnata));

        for(int i=xcir1;i<xcir2;i+=xcir3)
        {
            canvas.drawCircle(i, ycir1, rad, p);
        }
        for(int i=xcir1;i<xcir2;i+=xcir3)
        {
            canvas.drawCircle(i, ycir2, rad, p);
        }  

        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        canvas.drawPath(mPath, mPaint); 
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 2;

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }
    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
            mX = x;
            mY = y;
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        canvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        mPath.reset();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        Log.i("me.getRawX()",""+ event.getRawX());
        Log.i("me.getRawY()",""+ event.getRawY());

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }
        return true;
    }
}

我在下面这一行的onSizeChanged()内收到错误:

mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);            

1 个答案:

答案 0 :(得分:0)

如果您的位图非常大,或者至少如果您释放应用程序内存几乎耗尽,则新位图不再适合应用程序内存,因为旧的位图仍然存在(直到垃圾收集器被丢弃)并解放了它)

您可以通过(显式)首先释放旧位图的内存来解决您的问题。

使用recycle()方法:

protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  if(mBitmap != null) {
    // Explicitly free memory of old bitmap
    mBitmap.recycle();
  }
  mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);            

  // Rest of code
}

您可能希望在clear()方法中执行相同操作。