我有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);
}
}
}
答案 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;在构造函数中准备的位图。也许它应该释放记忆。