AsyncTask不释放内存

时间:2015-06-29 11:56:52

标签: java android memory-leaks bitmap android-asynctask

我有AsyncTask用指定的颜色替换位图的像素颜色,除非像素不是黑色。

AsyncTask类被声明为Activity的内部类。问题是在任务完成后没有释放内存,在几次AsyncTask调用之后我得到的内存错误不足。

我试图在onPostExecute中取消/回收bmp而没有成功:(

这是Asynctask和Activity类:

public class FloodFillActivity extends SherlockActivity {

    public static final String IMG = null;
    Context con;
    public Bitmap currentbmp;
    private String imgfile;
    public int replacecolor;
    public ImageView showcolor;
    private AdView mAdView;

    // A thread, that will be used to execute code in parallel with the UI
    // thread.
    public Thread mThread;
    // Create a thread handler to queue code execution on a thread.
    private Handler mHandler;
    // Boolean to determine whether a thread should continue processing or if it
    // should stop.
    public boolean isThreadBroken = false;
    // Runnable counter for progress bar.
    private int mRunnableCounter = 0;

    // The id of the currently selected color.
    public int selectedColor = Color.BLACK;

    // Define whether or not fill is occuring.
    public boolean isFillEnabled = false;

    // Define whether or not fill mode is enabled (if not, then the mode is
    // considered draw mode).
    public boolean isFillModeEnabled = false;
    // Define whether ot not erase mode is enabled (this check is necessary to
    // take precedence over fillMode.
    public boolean isEraseModeEnabled = false;

    // Set the SurfaceView Thread properties.
    private SurfaceHolder mOurHolder;
    private Thread mOurThread = null;
    //  ImageButton btnsave,btnshare,btnreset;


    // Image metrics
    public int imageWidth;
    public int imageHeight;

    // Set the GFX properties.

    // Boolean for determining whether or not the canvas should be cleared for
    // the next image load.
    public boolean isNextImage = false;
    // The picture bitmap.
    public Bitmap pictureBitmap;

    public String paintBitmapName;

    // Bitmap buffers used when loading a new bitmap.
    // The picture bitmap.
    public Bitmap pictureBitmapBuffer;

    // The path bitmap.
    public Bitmap bitmap;
    // The canvas to draw on.
    public Canvas pathCanvas;
    // The canvas to fill on.
    public Canvas fillCanvas;
    // The canvas for all draws.
    public Canvas canvas;

    // The path buffers.
    private boolean mIsDrawn = false;

    // Set brush properties
    // Set a brush emboss.
    public MaskFilter emboss;
    // Set a brush blur.
    public MaskFilter blur;
    // The color of the path.
    public Paint paint;
    public Paint bitmapPaint;
    // The path to draw in draw mode.
    public Path mPath;

    // Cehck to see if data is being restored.
    public boolean isSavedData;

    // A list of points to floodfill whenever this tool is used.
    private boolean[][] mFloodfillList;
    // A list of points to floodfill whenever this tool is used.
    private boolean[][] mStrokefillList;

    private Context mContext;


    public FloodFillActivity() {
        replacecolor = 0xffff0000;
        imgfile = null;
        currentbmp = null;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.floodfill);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#c5d951")));
        con = this;
        mAdView = (AdView) findViewById(R.id.adViewad);
        mAdView.loadAd(new AdRequest.Builder().build());
        imgfile = getIntent().getStringExtra(IMG);

        ImageView imageview = (ImageView) findViewById(R.id.floodfill);
        ImageView imageview1 = (ImageView) findViewById(R.id.colorpal);
        showcolor = (ImageView) findViewById(R.id.showcolor);
        showcolor.setBackgroundColor(replacecolor);

        try {
            imageview.setImageDrawable(Drawable.createFromStream(getAssets().open(imgfile), null));
            imageview1.setImageDrawable(Drawable.createFromStream(getAssets().open("CATIMAGE/color.png"), null));
            imageview1.setOnTouchListener(new android.view.View.OnTouchListener() {

                Bitmap pmap;

                public boolean onTouch(View view, MotionEvent motionevent) {
                    try {
                        Point point = new Point();
                        point.x = (int) motionevent.getX();
                        point.y = (int) motionevent.getY();
                        ImageView imageview2 = (ImageView) findViewById(R.id.colorpal);
                        imageview2.buildDrawingCache();
                        pmap = imageview2.getDrawingCache();
                        pathCanvas = new Canvas(pmap);
                        replacecolor = pmap.getPixel(point.x, point.y);
                        showcolor.setBackgroundColor(replacecolor);
                    } catch (Exception exception) {
                    }
                    return true;
                }


            });


        } catch (Exception exception) {
        }


        imageview.setOnTouchListener(new OnTouchListener() {

            Bitmap bmap;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub

                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    Point point = new Point();
                    point.x = (int) event.getX();
                    point.y = (int) event.getY();
                    ImageView imageview2 = (ImageView) findViewById(R.id.floodfill);
                    if (bmap == null) {
                        imageview2.buildDrawingCache();
                        bmap = imageview2.getDrawingCache();
                    }
                    imageWidth = bmap.getWidth();
                    imageHeight = bmap.getHeight();
                    int i = bmap.getPixel(point.x, point.y);
                    int j = replacecolor;
                    (new TheTask(bmap, point, i, j)).execute(new Void[0]);

                }
                return true;
            }
        });

    }

    /**
     * Colors all pixels from the flood fill algorithm.
     */
    public void colorPixels(Bitmap picture, int replacementColor) {
        // Both arrays are the same size, so just choose one to control the
        // iteration.
        for (int i = 0; i < mFloodfillList.length; i++) {
            for (int j = 0; j < mFloodfillList[i].length; j++) {
                if (mFloodfillList[i][j] != false) {
                    picture.setPixel(i, j, replacementColor);
                }
                if (mStrokefillList[i][j] != false) {
                    picture.setPixel(i, j, replacementColor);
                }
            }
        }
    }

    /**
     * Clears the stroke and floodfill pixel lists.
     */
    public void clearPixelLists() {
        mStrokefillList = null;
        mFloodfillList = null;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getSupportMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {

        ImageView imageview2 = (ImageView) findViewById(R.id.floodfill);
        final String s = "Image_" + String.valueOf(System.currentTimeMillis());
        switch (menuItem.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                return true;
            case R.id.save:
                if (currentbmp == null) {
                    imageview2.buildDrawingCache();
                    currentbmp = imageview2.getDrawingCache();
                }

                Media.insertImage(getContentResolver(), currentbmp, s, null);
                Toast.makeText(getApplicationContext(), "Save to Gallery", Toast.LENGTH_SHORT).show();
                return true;

            case R.id.share:

                if (currentbmp == null) {
                    imageview2.buildDrawingCache();
                    currentbmp = imageview2.getDrawingCache();
                }

                String share = Media.insertImage(getContentResolver(), currentbmp, s, null);
                Intent intent = new Intent("android.intent.action.SEND");
                intent.putExtra("android.intent.extra.SUBJECT", "Check out the holiday card I made");
                intent.putExtra("android.intent.extra.STREAM", Uri.parse(share));
                intent.setType("image/jpeg");
                startActivity(Intent.createChooser(intent, "Choose an app to share with"));

                return true;

            case R.id.repeat:
                try {
                    Drawable drawable = Drawable.createFromStream(getAssets().open(imgfile), null);
                    imageview2.setImageDrawable(drawable);
                    imageview2.buildDrawingCache();
                } catch (IOException ioexception1) {
                    ioexception1.printStackTrace();
                }
                return true;

            default:
                return super.onOptionsItemSelected(menuItem);
        }

    }



   private class TheTask extends AsyncTask {

        Bitmap bmp;
        Point pt;
        int replacementColor;
        int targetColor;

        public TheTask(Bitmap bitmap, Point point, int i, int j) {
            bmp = bitmap;
            pt = point;
            replacementColor = j;
            targetColor = i;
        }


        private boolean isBlack(int i, int j) {
            while (Color.red(i) == Color.green(i) && Color.green(i) == Color.blue(i) && Color.red(i) < 150 || i == j) {
                return true;
            }
            return false;
        }


        protected Void doInBackground(Void ... params) {
            bitmap=bmp;
            Point point=pt;
            Integer i = targetColor;
            Integer j = replacementColor;
            int k = bitmap.getWidth();
            int l = bitmap.getHeight();
            if (i != j) {
                LinkedList<Point> linkedlist = new LinkedList();
                do {
                    int i1 = point.x;
                    int j1;
                    for (j1 = point.y; i1 > 0 && !isBlack(bitmap.getPixel(i1 - 1, j1), j); i1--) {
                    }
                    boolean flag = false;
                    boolean flag1 = false;
                    while (i1 < k && !isBlack(bitmap.getPixel(i1, j1), j)) {
                        bitmap.setPixel(i1, j1, j);
                        if (!flag && j1 > 0 && !isBlack(bitmap.getPixel(i1, j1 - 1), j)) {
                            linkedlist.add(new Point(i1, j1 - 1));
                            flag = true;
                        } else if (flag && j1 > 0 && isBlack(bitmap.getPixel(i1, j1 - 1), j)) {
                            flag = false;
                        }
                        if (!flag1 && j1 < l - 1 && !isBlack(bitmap.getPixel(i1, j1 + 1), j)) {
                            linkedlist.add(new Point(i1, j1 + 1));
                            flag1 = true;
                        } else if (flag1 && j1 < l - 1 && isBlack(bitmap.getPixel(i1, j1 + 1), j)) {
                            flag1 = false;
                        }
                        i1++;
                    }
                    point = linkedlist.poll();
                } while (point != null);
            }
            return null;
        }

        protected void onPostExecute(Object obj) {
            onPostExecute((Void) obj);
        }

        protected void onPostExecute(Void void1) {
            ImageView imageV = (ImageView) findViewById(R.id.floodfill);
//            ((BitmapDrawable)imageV.getDrawable()).getBitmap().recycle(); //causes "can not reuse a recycled bitmap" on second-time run
            imageV.setImageBitmap(bmp);
        }

        @Override
        protected Object doInBackground(Object... params) {
            return doInBackground((Void[]) params);
        }
    }
}

3 个答案:

答案 0 :(得分:0)

问题是你想什么时候释放内存!

@Override
protected void onPause(){

  super.onPause();
  Drawable drawable = imageV.getDrawable(); // declare this ImageView Globally
  if (drawable instanceof BitmapDrawable) {
    BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
    Bitmap bitmap = bitmapDrawable.getBitmap();
    bitmap.recycle();
    imageV.setImageBitmap(null);  // edited
  }

}

您应该将以上代码段放在onPause();而不是onPostExecute();中,因为到那时您的位图仍在使用中。

答案 1 :(得分:0)

首先,您的变量名称看起来像是启用了minify的代码。使您的代码非常难以阅读。

其次,您需要回收位图:

  protected void onPostExecute(Void void1) {
        ImageView imageV = (ImageView) findViewById(R.id.floodfill);
        ((BitmapDrawable)imageV.getDrawable()).getBitmap().recycle();
        imageV.setImageBitmap(bmp);
    }

答案 2 :(得分:0)

尝试不使用bitmap=bmp;的doInBackground()中的第一个语句(此处&#34;位图&#34;是活动外部类&#39;位图)并使用Asynctask&#39对像素进行处理; s&#34; bmp&#34;在构造函数中准备的位图。也许它应该释放记忆。