美文网首页
关于BitmapFactory.decode

关于BitmapFactory.decode

作者: EvilsoulM | 来源:发表于2015-11-04 23:13 被阅读3517次

最近使用picasso遇到一个问题,picasso load在某些机子上load本地图片load不出来java.io.IOException: Cannot reset picasso官方也没有解决这个问题,只好自己写一个加载本地资源的库,也遇到了不少坑

Decode内存占用过大

这个问题还是由于自己对于BitmapFactory decode了解的不够仔细,先贴出原始代码吧


    /**
     * 根据imageview宽高 decode 图片
     */
    public static Bitmap decodeStream(InputStream is, ImageView imageView) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;

        //获取imageview想要显示的宽和高
        ImageSize imageViewSize = getImageViewSize(imageView);
        opts.inSampleSize = ImageUtils.calculateInSampleSize(opts,
                imageViewSize.getWidth(), imageViewSize.getHeight());

        opts.inJustDecodeBounds = false;

        return BitmapFactory.decodeStream(is, null, opts);
    }

这段代码貌似乍看没什么问题,考虑到了imageview加载过大图片的问题(ImageUtils.calculateInSampleSize),也用了inJustDecodeBounds属性,在native decode 不生成bitmap,获取bitmap宽和高,根据宽高压缩图片。

运行的时候发现,内存一个劲的上升,查了半天才发现,少写了一句decode...


    /**
     * 根据imageview宽高 decode 图片
     */
    public static Bitmap decodeStream(InputStream is, ImageView imageView) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        //这行代码,如果没有这行代码,native就不会decode流,其实很简单
        //低下你调用什么decode在inJustDecodeBounds = true;下面你就要写一样的方法先在native decode bitmap获取宽高
        BitmapFactory.decodeStream(is, null, opts);

        //获取imageview想要显示的宽和高
        ImageSize imageViewSize = getImageViewSize(imageView);
        opts.inSampleSize = ImageUtils.calculateInSampleSize(opts,
                imageViewSize.getWidth(), imageViewSize.getHeight());

        opts.inJustDecodeBounds = false;

        return BitmapFactory.decodeStream(is, null, opts);
    }

Android: SkImageDecoder:: Factory returned null

解决了上面一个问题后,图片还是load不出来...也没有什么异常或者crash的日志,只看到logcat 里面解析图片的时候会报Android: SkImageDecoder:: Factory returned null 查了下说是 “第一次取图片尺寸的时候is这个InputStream被使用过了,再真正取图片的时候又使用了这个InputStream,此时流的起始位置已经被移动过了,需要调用is.reset()来重置,然后再decodeStream(imgInputStream, null, options)就没问题了。 ”
于是乎就将代码改为


    /**
     * 根据imageview宽高 decode 图片
     */
    public static Bitmap decodeStream(InputStream is, ImageView imageView) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;

        BitmapFactory.decodeStream(is, null, opts);
        is.reset();//加入reset
       
        ImageSize imageViewSize = getImageViewSize(imageView);
        opts.inSampleSize = ImageUtils.calculateInSampleSize(opts,
                imageViewSize.getWidth(), imageViewSize.getHeight());

        opts.inJustDecodeBounds = false;

        return BitmapFactory.decodeStream(is, null, opts);
    }

java.io.IOException

加入reset之后又遇到IOException 查了些也没具体说为什么就改成下面的方法了,果然好了

 /**
     * 根据imageview宽高 decode 图片
     */
    public static Bitmap decodeStream(InputStream is, ImageView imageView) {
        Bitmap bitmap = null;
        BufferedInputStream buffer = null;

        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;

        try {
            int buffersize = 16 * 1024;
            buffer = new BufferedInputStream(is, buffersize);
            buffer.mark(16 * 1024);
            BitmapFactory.decodeStream(buffer, null, opts);
            buffer.reset();

            //获取imageview想要显示的宽和高
            ImageSize imageViewSize = getImageViewSize(imageView);
            opts.inSampleSize = ImageUtils.calculateInSampleSize(opts,
                    imageViewSize.getWidth(), imageViewSize.getHeight());

            opts.inJustDecodeBounds = false;
            bitmap = BitmapFactory.decodeStream(buffer, null, opts);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ImageUtils.closeQuietly(buffer);
            ImageUtils.closeQuietly(is);
        }
        return bitmap;
    }

但是,第二天使用oppo R7的时候还是报哪个错误,load不出来图。逐改成,确实解决了问题,都能顺利的decode图正常显示了。

/**
     * 根据imageview宽高 decode 图片
     */
    public static Bitmap decodeStream(InputStream is, ImageView imageView) {
        Bitmap bitmap = null;
        BufferedInputStream bis = null;
        ByteArrayOutputStream baos = null;

        try {
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.inJustDecodeBounds = true;

            bis = new BufferedInputStream(is);
            baos = new ByteArrayOutputStream();

            byte buffer[] = new byte[1024];
            int len;
            while ((len = bis.read(buffer, 0, buffer.length)) > 0) {
                baos.write(buffer, 0, len);
            }

            byte[] imageData = baos.toByteArray();

            BitmapFactory.decodeByteArray(imageData, 0, imageData.length, opts);

            //获取imageview想要显示的宽和高
            ImageSize imageViewSize = getImageViewSize(imageView);
            opts.inSampleSize = ImageUtils.calculateInSampleSize(opts,
                    imageViewSize.getWidth(), imageViewSize.getHeight());

            opts.inJustDecodeBounds = false;
            bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, opts);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.close(bis);
            IOUtils.close(baos);
            IOUtils.close(is);
        }
        return bitmap;
    }

网上搜了好多也没找到具体原因,只能看源代码了:

if (!is.markSupported()) {  
    is = new BufferedInputStream(is, DECODE_BUFFER_SIZE);  
}  
// so we can call reset() if a given codec gives up after reading up to  
// this many bytes. FIXME: need to find out from the codecs what this  
// value should be.  
is.mark(1024);  

于是看明白了,第一次取图片尺寸的时候is这个InputStream被使用过了,再真正取图片的时候又使用了这个InputStream,此时流的起始位置已经被移动过了,需要调用is.reset()来重置,然后再decodeStream(imgInputStream, null, options)就没问题了。 但是注意一个问题,is.mark(1024)是SDK中写死的,如果图片的大小超过1024字节,第一次decode取尺寸之后调用is.reset()会抛出IOException

http://stackoverflow.com/questions/10240042/ioexception-cannot-load-file

相关文章

  • 关于BitmapFactory.decode

    最近使用picasso遇到一个问题,picasso load在某些机子上load本地图片load不出来java.i...

  • Android中高效的显示图片 - 非UI线程加载

    在Android中高效的显示图片 - 加载大图一文中讲到了BitmapFactory.decode*方法的使用,但...

  • 关于关于关于

    他们爱他们自己,不爱你 他们爱你是他们的母亲妻子女儿姐妹 他们不爱你 直到你死的时候,爱才产生,与遗忘同时 那也不...

  • 光明人生

    关于出生 关于成长 关于求学 关于青春期 关于恋爱 关于择业 关于婚姻 关于养生 关于家庭 关于人际 关于教子 关...

  • 「梦雅的简动力」打卡计时65天

    * 关于人生 * 关于梦想 * 关于方向 * 关于创业 * 关于投资 * 关于成败 * 关于个性 * 关于高度 *...

  • 关于

    关于两个人? 关于100步? 关于回头? 关于深情? 关于家庭? 关于孩子? 关于成长? 关于伤痛? 关于怀抱? ...

  • 2017新手妈妈年终总结

    关于购物 关于体重 关于减肥 关于纪念日 关于生活态度 关于上班 关于职场晋升加薪 关于睡眠 关于抱孩子 关于发型...

  • 2018-11-28

    关于流浪、关于随心、关于自由、关于世俗、关于规则、关于坦诚、关于真我、关于好奇心、关于对这整个世界的态度、关于整个...

  • 一首歌的时间

    认真的 想理出点思绪 关于今天关于明天 关于工作关于梦想 关于冬天关于夜晚 关于阳光关于浪花 关于木马关于窗花 关...

  • 最近的各种关于

    关于运动,关于中文阅读,关于英文听力,关于口算。 关于专注,关于目标,关于举家迁移。 关于对正确的过于执着,关于对...

网友评论

      本文标题:关于BitmapFactory.decode

      本文链接:https://www.haomeiwen.com/subject/ortchttx.html