android using flood fill algorithm getting out of memory exception

江枫思渺然 提交于 2019-12-18 05:26:10

问题


after your suggestions i got working code:

public class FingerPaint extends Activity {

private RelativeLayout drawingLayout;
private MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    myView = new MyView(this);
    setContentView(myView);
    drawingLayout.addView(myView);
}

public class MyView extends View {

    private Paint paint;
    private Path path;
    Bitmap mBitmap;
    ProgressDialog pd;
    final Point p1 = new Point();
    Canvas canvas;
    //Bitmap mutableBitmap ;
    public MyView(Context context) {
        super(context);

        this.paint = new Paint();
        this.paint.setAntiAlias(true);
        pd = new ProgressDialog(context);
        this.paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeWidth(5f);
        mBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.paint).copy(Bitmap.Config.ARGB_8888, true);


        this.path = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        this.canvas = canvas;
        this.paint.setColor(Color.GREEN);
        canvas.drawBitmap(mBitmap, 0, 0, paint);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:

            p1.x = (int) x;
            p1.y = (int) y;
            final int sourceColor = mBitmap.getPixel((int) x, (int) y);
            final int targetColor = paint.getColor();
            new TheTask(mBitmap, p1, sourceColor, targetColor).execute();
            invalidate();
        }
        return true;
    }

    public void clear() {
        path.reset();
        invalidate();
    }

    public int getCurrentPaintColor() {
        return paint.getColor();
    }

    class TheTask extends AsyncTask<Void, Integer, Void> {

        Bitmap bmp;
        Point pt;
        int replacementColor, targetColor;

        public TheTask(Bitmap bm, Point p, int sc, int tc) {
            this.bmp = bm;
            this.pt = p;
            this.replacementColor = tc;
            this.targetColor = sc;
            pd.setMessage("Filling....");
            pd.show();
        }

        @Override
        protected void onPreExecute() {
            pd.show();

        }

        @Override
        protected void onProgressUpdate(Integer... values) {

        }

        @Override
        protected Void doInBackground(Void... params) {
            FloodFill f = new FloodFill();
            f.floodFill(bmp, pt, targetColor, replacementColor);
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            pd.dismiss();
            invalidate();
        }
    }
}

// flood fill

public class FloodFill {
    public void floodFill(Bitmap image, Point node, int targetColor,
            int replacementColor) {
        int width = image.getWidth();
        int height = image.getHeight();
        int target = targetColor;
        int replacement = replacementColor;
        if (target != replacement) {
            Queue<Point> queue = new LinkedList<Point>();
            do {

                int x = node.x;
                int y = node.y;
                while (x > 0 && image.getPixel(x - 1, y) == target) {
                    x--;

                }
                boolean spanUp = false;
                boolean spanDown = false;
                while (x < width && image.getPixel(x, y) == target) {
                    image.setPixel(x, y, replacement);
                    if (!spanUp && y > 0
                            && image.getPixel(x, y - 1) == target) {
                        queue.add(new Point(x, y - 1));
                        spanUp = true;
                    } else if (spanUp && y > 0
                            && image.getPixel(x, y - 1) != target) {
                        spanUp = false;
                    }
                    if (!spanDown && y < height - 1
                            && image.getPixel(x, y + 1) == target) {
                        queue.add(new Point(x, y + 1));
                        spanDown = true;
                    } else if (spanDown && y < height - 1
                            && image.getPixel(x, y + 1) != target) {
                        spanDown = false;
                    }
                    x++;
                }
            } while ((node = queue.poll()) != null);
        }
    }
}
}

Now it is working fine.ThanQ


回答1:


Use Async Task. Running every operation on Main Ui thread may cause's out of memory exception. My suggestion , use threads. Do Floodfill in background. Check this link. May help You. Fill the complete canvas but keep the bound fill area as it is like circle, rectangle

    private Paint paint;
private Path path;
Bitmap mBitmap;
ProgressDialog pd;
 final Point p1 = new Point();
Canvas canvas;
private static final float TOUCH_TOLERANCE = 4;
float mX,mY;

public DrawingView(Context context ) {
    super(context);

    this.paint = new Paint();
    this.paint.setAntiAlias(true);
    pd= new ProgressDialog(context);
    this.paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeWidth(5f);
    mBitmap= BitmapFactory.decodeResource(getResources(), R.drawable.rose_sketch);
    this.path = new Path();
}

@Override
protected void onDraw(Canvas canvas) {
    this.canvas=canvas;
    this.paint.setColor(Color.GREEN);
    canvas.drawBitmap(mBitmap, 0, 0,paint);

}

@Override
public boolean onTouchEvent(MotionEvent event) {

    float x = event.getX();
    float y = event.getY();
    switch(event.getAction())
    {
    case MotionEvent.ACTION_DOWN:
    //final Point p1 = new Point();
    p1.x=(int) x;
    p1.y=(int) y;
    final int sourceColor=  mBitmap.getPixel((int)x,(int) y);
    final int targetColor = paint.getColor();
    new TheTask(mBitmap, p1, sourceColor, targetColor).execute();
    invalidate();    
    }
    return true;
}

public void clear() {
    path.reset();
    invalidate();
}
public int getCurrentPaintColor() {
    return paint.getColor();
}
class TheTask extends AsyncTask<Void, Integer, Void> {

    Bitmap bmp;
    Point pt;
    int replacementColor,targetColor;

    public TheTask(Bitmap bm,Point p, int sc, int tc)
    {
        this.bmp=bm;
        this.pt=p;
        this.replacementColor=tc;
        this.targetColor=sc;
        pd.setMessage("Filling....");
        pd.show();
    }
    @Override
    protected void onPreExecute() {
        pd.show();

    }

    @Override
    protected void onProgressUpdate(Integer... values) {

    }

    @Override
    protected Void doInBackground(Void... params) {
        FloodFill f= new FloodFill();
        f.floodFill(bmp,pt,targetColor,replacementColor);
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {     
        pd.dismiss();
        invalidate();
    }
}
}

USE FLOODFILL NOW.

 public class FloodFill {
public void floodFill(Bitmap image, Point node, int targetColor,
        int replacementColor) {
    int width = image.getWidth();
    int height = image.getHeight();
    int target = targetColor;
    int replacement = replacementColor;
    if (target != replacement) {
        Queue<Point> queue = new LinkedList<Point>();
        do {
            int x = node.x;
            int y = node.y;
            while (x > 0 && image.getPixel(x - 1, y) == target) {
                x--;
            }
            boolean spanUp = false;
            boolean spanDown = false;
            while (x < width && image.getPixel(x, y) == target) {
                image.setPixel(x, y, replacement);
                if (!spanUp && y > 0
                        && image.getPixel(x, y - 1) == target) {
                    queue.add(new Point(x, y - 1));
                    spanUp = true;
                } else if (spanUp && y > 0
                        && image.getPixel(x, y - 1) != target) {
                    spanUp = false;
                }
                if (!spanDown && y < height - 1
                        && image.getPixel(x, y + 1) == target) {
                    queue.add(new Point(x, y + 1));
                    spanDown = true;
                } else if (spanDown && y < height - 1
                        && image.getPixel(x, y + 1) != target) {
                    spanDown = false;
                }
                x++;
            }
        } while ((node = queue.poll()) != null);
    }
}
}

Edit:

One of the users commented that the solution @ Android flood-fill algorithm works faster than the solution posted here. So take look at the solution in the link although i haven't tested it myself.




回答2:


I have seen this problem with my code whenver there is some really complex computations going on in the UI thread. If you have implemented flood fill in the UI thread, the computations are causing 99% CPU usage due to which other applications and services are not getting thier share of the CPU. As a result, android will try to kill your app inorder to restore the integrity of the System. As a simple solution, try to offload your computations to a AsyncTask or a thread.




回答3:


I think you have to swich off the multitoutch of your screen because of that it went to out of memory....



来源:https://stackoverflow.com/questions/12669740/android-using-flood-fill-algorithm-getting-out-of-memory-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!