天天看點

使用Bitmap.createBitmap遇到的問題

Bitmap.java中createBitmap函數調用的是以下重構方法

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;
        
        canvas.setBitmap(bitmap);
        canvas.drawBitmap(source, srcR, dstR, paint);
        canvas.setBitmap(null);
 
        return bitmap;
    }      

注意發現其中有以下代碼

// 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;
 }      

以上代碼的邏輯是:如果源位圖是 immutable且請求傳回的位圖是和源位圖一樣的,則直接傳回源位圖,并不建立新位圖。

是以你在使用它的時候很可能會傳回一個你之前傳進來的bitmap。是以如果你把認為是臨時變量的bitmap回收掉之後,其實是把不該回收的也回收了。這時就會抛出詭異的bitmap回收問題,說是使用了recycled的bitmap。如果一定需要建立一個拷貝的話,可以嘗試使用Bitmap.copy(Config config, boolean isMutable)方法代替。

繼續閱讀