异常:trying to use a recycled bitmap android.graphics.Bitmap
概意:试图使用已经recycled的Bitmap
一般情况下我们在对Bitmap进行Matrix的各种缩放、平移等处理,然后createBitmap,再对之前的Bitmap进行recycle处理。
例如:
Bitmap oldBitmap= BitmapFactory.decodeFile(pathName);
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 0.5f);
Bitmap newBitmap= Bitmap.createBitmap(bitmapDecode, 0, 0,
oldBitmap.getWidth(), oldBitmap.getHeight(), matrix, true);
if(!oldBitmap.isRecycled()){
oldBitmap.recycle();
}
异常的根本问题出在“Bitmap.createBitmap”函数这里:
/**
* Returns an immutable bitmap from subset of the source bitmap,
* transformed by the optional matrix. The new bitmap may be the
* same object as source, or a copy may have been made. It is
* initialized with the same density as the original bitmap.
*
* If the source bitmap is immutable and the requested subset is the
* same as the source bitmap itself, then the source bitmap is
* returned and no new bitmap is created.
*
* @param source The bitmap we are subsetting
* @param x The x coordinate of the first pixel in source
* @param y The y coordinate of the first pixel in source
* @param width The number of pixels in each row
* @param height The number of rows
* @param m Optional matrix to be applied to the pixels
* @param filter true if the source should be filtered.
* Only applies if the matrix contains more than just
* translation.
* @return A bitmap that represents the specified subset of source
* @throws IllegalArgumentException if the x, y, width, height values are
* outside of the dimensions of the source bitmap, or width is <= 0,
* or height is <= 0
*/
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
Matrix m, boolean filter) {
checkXYSign(x, y);
checkWidthHeight(width, height);
if (x + width > source.getWidth()) {
throw new IllegalArgumentException("x + width must be <= bitmap.width()");
}
if (y + height > source.getHeight()) {
throw new IllegalArgumentException("y + height must be <= bitmap.height()");
}
// check if we can just return our argument unchanged
if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
height == source.getHeight() && (m == null || m.isIdentity())) {
return source;
}
int neww = width;
int newh = height;
Canvas canvas = new Canvas();
Bitmap bitmap;
Paint paint;
Rect srcR = new Rect(x, y, x + width, y + height);
RectF dstR = new RectF(0, 0, width, height);
Config newConfig = Config.ARGB_8888;
final Config config = source.getConfig();
// GIF files generate null configs, assume ARGB_8888
if (config != null) {
switch (config) {
case RGB_565:
newConfig = Config.RGB_565;
break;
case ALPHA_8:
newConfig = Config.ALPHA_8;
break;
//noinspection deprecation
case ARGB_4444:
case ARGB_8888:
default:
newConfig = Config.ARGB_8888;
break;
}
}
if (m == null || m.isIdentity()) {
bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());
paint = null; // not needed
} else {
final boolean transformed = !m.rectStaysRect();
RectF deviceR = new RectF();
m.mapRect(deviceR, dstR);
neww = Math.round(deviceR.width());
newh = Math.round(deviceR.height());
bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig,
transformed || source.hasAlpha());
canvas.translate(-deviceR.left, -deviceR.top);
canvas.concat(m);
paint = new Paint();
paint.setFilterBitmap(filter);
if (transformed) {
paint.setAntiAlias(true);
}
}
// The new bitmap was created from a known bitmap source so assume that
// they use the same density
bitmap.mDensity = source.mDensity;
bitmap.mIsPremultiplied = source.mIsPremultiplied;
canvas.setBitmap(bitmap);
canvas.drawBitmap(source, srcR, dstR, paint);
canvas.setBitmap(null);
return bitmap;
}
着重描述“The new bitmap may be the same object as source”,创建的bitmap可能是同一个对象,why?函数中的代码说明了一切:
// check if we can just return our argument unchanged
if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
height == source.getHeight() && (m == null || m.isIdentity())) {
return source;
}
如果创建新的bitmap没有变化且x,y,宽高且matrix也是相同的,那么直接将来来源要出的bitmap直接返回,如果createBitmap后直接recycle然后再使用能不异常吗。
解决方法:
Bitmap oldBitmap= BitmapFactory.decodeFile(pathName);
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 0.5f);
Bitmap newBitmap= Bitmap.createBitmap(bitmapDecode, 0, 0,
oldBitmap.getWidth(), oldBitmap.getHeight(), matrix, true);
if(!oldBitmap.isRecycled() && !oldBitmap.equals(newBitmap)){
oldBitmap.recycle();
}
主要判断“!oldBitmap.equals(newBitmap)”后再进行recycle。或者在createBitmap之前就判断oldBitmap是需要Matrix处理。