移动云

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
移动云 门户 移动应用开发 Android开发 查看内容

慎用Bitmap.createBitmap

2012-9-18 16:46| 发布者: admin| 查看: 22839| 评论: 0|原作者: T268

摘要: 碰到一个诡异的bitmap回收问题,抛出了使用了recycled的bitmap。 最终分析是Bitmap.createBitmap(Bitmap bitmap)造成的,Bitmap.createBitmap(。。。)都有此可能。 这个方法的注释如下: Returns an immutable bit ...
碰到一个诡异的bitmap回收问题,抛出了使用了recycled的bitmap。
最终分析是Bitmap.createBitmap(Bitmap bitmap)造成的,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.

所以你在使用它的时候很可能会返回给你一个你传进来的bitmap。

所以如果你按照你的设计把那个认为是临时变量的bitmap回收掉之后,殊不知不该回收的也回收了。

之前好像在哪里看到过有朋友说用Bitmap.createBitmap构造出来的bitmap回收的时候把传入的也连带回收了,并且没找到原因。当时也没在意,并且那边也没有结贴。现在想起来,估计就是这个方法造成的。

翻看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;
        }

因此,在满足这个逻辑的情况下,createBitmap把传进来的source直接返回了。

所以对这个方法慎用吧,需要保证创建一个拷贝的可以尝试使用Bitmap.copy(Config config, boolean isMutable)来完成设计上的需要。


鲜花

握手

雷人

路过

鸡蛋

相关分类

小黑屋|管理员QQ:44994224|邮箱(t268studio@gmail.com)|Archiver|MCLOUDER

GMT+8, 2024-5-4 16:50 , Processed in 0.030464 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

返回顶部