trying to use a recycled bitmap android.graphics.Bitmap

尝试使用已回收的Bitmap导致Android应用抛出异常。问题源于Bitmap.createBitmap操作,当新Bitmap与源Bitmap对象相同且未经修改时,直接回收源Bitmap会造成后续使用异常。解决方法是在回收前确保新旧Bitmap不相等,或者在处理前判断Bitmap是否需要矩阵变换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常: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处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值