Android:画布上的内存不足错误invalidate()

时间:2013-10-18 12:08:43

标签: android android-canvas out-of-memory

 10-18 17:38:41.400: E/dalvikvm-heap(24493): Out of memory on a 8294416-byte allocation.

我在屏幕的中央绘制一个圆形图像,并将其划分为多边形等坐标。但我的问题是当用户触摸坐标时(有6个坐标可用)我正在将背景图像重新绘制到画布上。

它在最初的几次触摸中工作正常,但如果我触摸超过7到8次,那么由于内存分配以及有时在创建画布的屏幕加载时崩溃会导致崩溃。下面是画布代码实现。

public class CircleView extends View implements OnTouchListener{

private List<CircleViewBean> mMenuEntries = new ArrayList<CircleViewBean>();
private OnCellTouchListener mOnCellTouchListener = null;
public interface OnCellTouchListener {
    public void onTouch(Wedge cell);
}
private Shader mShader;

private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

private float screen_density = getContext().getResources().getDisplayMetrics().density;


private int mMinSize = scalePX(60);             //Radius of inner ring size
private int mMaxSize = scalePX(170);                //Radius of outer ring size
private int mWedgeQty = 8;
private int xPosition = scalePX(120);           //Center X location of Radial Menu
private int yPosition = scalePX(120);           //Center Y location of Radial Menu
int touchIndex = -1;
private Wedge[] mWedges;

private RectF mViewRect = new RectF();


private int scalePX( int dp_size )
{
   int px_size = (int) (dp_size * screen_density + 0.5f);
   return px_size;
}


public CircleView(Context context) {
    this(context, null);
}

/**
 * Constructor used when this widget is created from a layout file.
 */
public CircleView(Context context, AttributeSet attrs) {
    super(context, attrs);
    HashMap<String, String> device = Constants.getDeviceDetails(getResources().getDisplayMetrics().heightPixels);
    int size = Integer.parseInt(device.get("circle_size"));
    this.xPosition = size==400? size/2 + 25 : size/2;
    this.yPosition = size==400? size/2 + 25 : size/2;
    Log.d("yPosition", yPosition+"-"+xPosition);
    mMinSize = Integer.parseInt(device.get("in_arc"));
    mMaxSize = Integer.parseInt(device.get("out_arc"));
    setBackgroundResource(R.drawable.centre_wheel);
    determineWedges();

}

private void determineWedges() {
    int entriesQty = mMenuEntries.size();
    if ( entriesQty > 0) {
        mWedgeQty = entriesQty;

        float degSlice = 360 / mWedgeQty;
        float start_degSlice = 270 - (degSlice/2);
        //calculates where to put the images

        this.mWedges = new Wedge[mWedgeQty];

        double mid = 0, min = 0, max = 0;
        for(int i = 0; i < this.mWedges.length; i++) {
            this.mWedges[i] = new Wedge(xPosition, yPosition, mMinSize, mMaxSize, (i
                    * degSlice)+start_degSlice, degSlice, mMenuEntries.get(i).getIndex());

            mid = this.mWedges[i].midValue = normalizeAngle( ((i * degSlice) + start_degSlice + degSlice) / 2 );
            min = normalizeAngle( (i * degSlice) + start_degSlice );
            max = normalizeAngle( (i * degSlice) + start_degSlice + degSlice);

            this.mWedges[i].minValue = min;
            this.mWedges[i].midValue = mid;
            this.mWedges[i].maxValue = max;

            mViewRect.union( new RectF( mWedges[i].getWedgeRegion().getBounds() ) );
        }

        mShader = new RadialGradient(xPosition, yPosition, mMaxSize, new int[] { 0xff595756, 0xffCCC5C3, 0xf878280}, null, Shader.TileMode.MIRROR);
        invalidate();
    }
} 

@Override
public void onDraw(Canvas canvas) {

    canvas.scale(getWidth() / mViewRect.width(), getHeight() / mViewRect.width(), xPosition, yPosition);
    //Saving the canvas and later restoring it so only this image will be rotated.
    canvas.save(Canvas.MATRIX_SAVE_FLAG);

    for (int i = 0; i < mWedges.length; i++) {
        Wedge f = mWedges[i];
        mPaint.setColor(Color.TRANSPARENT);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(f, mPaint);
    }

    canvas.restore();

    canvas.save();
    canvas.restore();

    mPaint.setShader( mShader );  
}


private double normalizeAngle(double angle) {
    if(angle >= 0) {
        while( angle > 360 ) {
            angle -= 360;
        }
    }
    else {
        while( angle < -360) {
            angle += 360;
        }
    }
    return angle;
}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // TODO Auto-generated method stub
    int wmode = MeasureSpec.getMode(widthMeasureSpec);
    int hmode = MeasureSpec.getMode(heightMeasureSpec);
    int wsize = MeasureSpec.getSize(widthMeasureSpec);
    int hsize = MeasureSpec.getSize(heightMeasureSpec);

    int width = (int)mViewRect.width();
    int height = (int) mViewRect.height();

    if (wmode == MeasureSpec.EXACTLY) {
        width = wsize;
    }
    if (hmode == MeasureSpec.EXACTLY) {
        height = hsize;
    }
    this.setMeasuredDimension(width, height);

    invalidate();

}

public class Wedge extends Path {
    private int x, y;
    private int InnerSize, OuterSize;
    private float StartArc;
    private float ArcWidth;
    private Region mWedgeRegion;
    private int index=0;
    public double minValue;
    public double midValue;
    public double maxValue;
    private Wedge(int x, int y, int InnerSize, int OuterSize, float StartArc, float ArcWidth, int category) {
        super();
        this.index = category;
        if (StartArc >= 360) {
            StartArc = StartArc-360;
        }

        minValue = midValue = maxValue = 0;
        mWedgeRegion = new Region();
        this.x = x; this.y = y;
        this.InnerSize = InnerSize;
        this.OuterSize = OuterSize;
        this.StartArc = StartArc;
        this.ArcWidth = ArcWidth;
        this.buildPath();
    }
    public int getCategoryIndex(){
        return this.index;
    }
    public String toString() {
        return minValue + "  " + midValue + "  " + maxValue;
    }
    /**
     * 
     * @return the bottom rect that will be used for intersection 
     */
    public Region getWedgeRegion() {
        return mWedgeRegion;
    }

    private void buildPath() {

        final RectF rect = new RectF();
        final RectF rect2 = new RectF();

        //Rectangles values
        rect.set(this.x-this.InnerSize, this.y-this.InnerSize, this.x+this.InnerSize, this.y+this.InnerSize);
        rect2.set(this.x-this.OuterSize, this.y-this.OuterSize, this.x+this.OuterSize, this.y+this.OuterSize);

        this.reset();
        //this.moveTo(100, 100);
        this.arcTo(rect2, StartArc, ArcWidth);
        this.arcTo(rect, StartArc+ArcWidth, -ArcWidth);

        this.close();

        mWedgeRegion.setPath( this, new Region(0,0,480,800) );
    }
}

public boolean addMenuEntry(CircleViewBean menuEntry) {
    mMenuEntries.add(menuEntry);
    determineWedges();
    return true;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d("", "touch");
    if(event.getAction() == MotionEvent.ACTION_UP){
        if(mOnCellTouchListener!=null && touchIndex >-1){
            int i=0;
            for(Wedge day : mWedges) {
                if(day.getWedgeRegion().getBounds().contains((int)event.getX(), (int)event.getY()) && touchIndex==i) {
                    mOnCellTouchListener.onTouch(mWedges[touchIndex]);
                    break;
                }
                i++;
            }
        }
    }else if(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE){
        int i=0;
        for(Wedge day : mWedges) {
            if(day.getWedgeRegion().getBounds().contains((int)event.getX(), (int)event.getY())) {
                touchIndex = i;
                setBackgroundResource(mMenuEntries.get(touchIndex).getIcon());
            }
            i++;
        }
        //invalidate();
    }
    return true;
}
public void setOnCellTouchListener(OnCellTouchListener p) {
    mOnCellTouchListener = p;
}

public boolean onTouch(View v, MotionEvent event) {
    return false;
}

}

1 个答案:

答案 0 :(得分:0)

我将此行放在清单文件

中的应用程序选项卡中
android:largeHeap="true"

这需要最低api级别11.