美文网首页
用BitmapFactory.decodeStream()方法计

用BitmapFactory.decodeStream()方法计

作者: 临星hfuu | 来源:发表于2020-04-12 12:59 被阅读0次

在学习图片加载时图片很大的时候直接加载到内存或则直接原图绘制到 ImageView中会导致OOM问题;

解决思路是利用BitmapFactory的系列方法中有个带有 BitmapFactory.Options 参数的方法,这个参数可以通过设置

options.inSampleSize = Int ;  //设置图片采样率
这个图片采样率的意思就是几个像素点取一个,例如原图的像素为 1000 * 1000  设置采样率为2
那么就是在横向和纵向上每2个像素点采样一次 最终得到一个 (1000/2)*(1000/2)的bitmap图片加载到内存中,从而达到占用内存变小的目的;
但是我们获取的图片的大小是不确定的,我们的控件尺寸在不同分辨率的设备上大小也不一样;所以我们不能给一个固定的采样率,需要根据获取的图片大小和控件大小来决定采样率;

计算采样率:
options.inJustDecodeBounds =true
options中该属性设置为true时,调用BitmapFactory的带options的系列方法,bitmap不会载入内存,方法返回null。但是方法会把bitmap的一些信息写入options,这样就可以在不消耗大量内存的情况下得到图片资源的尺寸信息;
这里以 BitmapFactory.decodeStream(inputStream,null,options)  方法为例:

val options = BitmapFactory.Options()
options.inJustDecodeBounds =true
BitmapFactory.decodeStream(inputStream,null,options)
//得到控件的宽高尺寸
val viewWidth =binding.imageView.measuredWidth
val viewHeight =binding.imageView.measuredHeight
//利用options中的outWidth 和 outHeight 参数和控件尺寸计算横向和纵向的最合适采样率
val x:Float = (options.outWidth/viewWidth).toFloat()
val y:Float = (options.outHeight/viewHeight).toFloat()
//下面这个是计算采样率的策略,可以有不同的策略;

//如果控件的宽高至少有一个是小于图片的宽高的时候才进行采样率计算
if ( viewHeight<options.outHeight || viewWidth<options.outWidth ) {
    // 取较大的那个作为采样率,也有的策略取小的那个 
     val s = if (x<y)  y  else  x
     options.inSampleSize = s.toInt(); //设置图片采样率
     Log.e("qqq",""+ s +">>>>>>>" + s.toInt())
}

设置好采样率后,重新把 options.inJustDecodeBounds = false 然后就可以采用上面的采样率加载图片到控件中了
val bitmap = BitmapFactory.decodeStream(inputStream,null,options)
imageView.setImageResource(bitmap)

这时候我以为大功告成了,结果发现 
图片竟然并没有显示出来,但是也并没有什么报错,第二次调用BitmapFactory.decodeStream(inputStream,null,options) 即时设置  options.inJustDecodeBounds = false 
返回的值还是null;怎么回事呢?查了一下说是我们需要在两次decode 之间将流重置  inputStream.reset() 一下 

好了加上这句在运行一下看看结果:

java.io.IOException: mark/reset not supported at java.io.InputStream.reset

???啥意思,大概就是说不支持 InputStream.reset,查了下,网上有朋友说是因为

当给定的流不支持mark和reset就会报这个错误,解决方案是用BufferedInputStream把原来的流包一层.什么时候会出现这种错误呢?获取到一个网络流,这个网络流不允许读写头来回移动,也就不允许mark/reset机制.
BufferedInputStream zipTest=new BufferedInputStream(zip);

说的很明白了,于是我们就回到上面的获取到inputStream的代码,按他说的包装一下:
val bufferedInputStream = new BufferedInputStream(inputStream);
然后在 BitmapFactory.decodeStream(bufferedInputStream,null,options) 中传入 bufferedInputStream;
val bitmap = BitmapFactory.decodeStream(inputStream,null,options)
这下总该可以了吧!!!

结果还是报错啦!!!

Caused by: java.io.IOException: Resetting to invalid mark

        at java.io.BufferedInputStream.reset(BufferedInputStream.java:450)

黑人问号脸????这个又是咋回事? 重置无效的标记?由于之间完全不了解这块的东西于是又搜了下资料,发现有篇相关的博客下的评论是这样的:

* The maximum read ahead allowed after a call to the      * <code>mark</code> method before subsequent calls to the      * <code>reset</code> method fail.      * Whenever the difference between <code>pos</code>     * and <code>markpos</code> exceeds <code>marklimit</code>,     * then the  mark may be dropped by setting     * <code>markpos</code> to <code>-1</code>.
mark(0)时没有意思的通俗的说如果你mark(1000)之后再读取1001个自己(超过1000),你就无法reset了,就是你上面的错误。很好理解:你想重新获取最近的1000个字节,可以你已经读取的自己超过了它,你当然无法回到开始的位置了。你在这里设置mark(0),之后只要调用了read方法就不能reset了!

咦?好像是在说这个reset()调用之间要用mark(Int)标记一下读取的字节size,读取超过了reset()就回不去了;
于是我又在包装bufferedInputStream后面加了一句:
bufferedInputStream.mark(1024*1024) //考虑到我读的是一个图片流应该不小把,字节给足!!!
最后再跑一下,终于成功加载出来了图片,而且也确实做到了动态计算采样率!

好了总算整明白怎么回事了!记录一下。

然后查资料的过程中还顺便了解到长图分区域加载,大概是这个类:BitmapRegionDecoder
具体看这篇大神的博客 https://www.jianshu.com/p/f576fd7313da

BitmapRegionDecoder

它提供了一系列静态方法构造实例

拿到实例后 通过 #decodeRegion() 方法,传入一个 Rect 和 一个BitmapFactory.Options 参数 即可解码出一张我们要的图片解码区域就是我们 Rect 指定的范围,拿到 Bitmap 后当然可以为所欲为了

相关文章

  • 用BitmapFactory.decodeStream()方法计

    在学习图片加载时图片很大的时候直接加载到内存或则直接原图绘制到 ImageView中会导致OOM问题; 解决思路是...

  • 育儿36计

    育儿方法千万种, 唯有科学育儿方法、良好的情绪控制能力及持之以恒的坚持,亲子教育36计,计计育儿好方法。 一、样板...

  • 控制

    早上一直很兴奋,用全脑图形结合的方法记住了36计。又练习了杯子,在查找36计小故事时,增加了对历史的了解。 午休时...

  • 案例计-PPT 17计

    用案例计3个方法中选取一种,写一个你公司产品或者在PPT演讲力36计(训练营)学习的案例 销售:王姐, 公司最近哪...

  • 数组中找重复数字,不改变数组

    明显如果你用一个辅助数组,复制下来,然后按照上面的方法来算的话,完全没有问题的.2.另外的话,下面的方法是用二分计...

  • 巧记三十六计(7—10)

    三十六计第二套敌战计,指的是第七计到第十二计。 今天先说一下第七计到第十计的记忆方法。明天再说十一十二计。 三十六...

  • 巧记三十六计(第一计)

    目的:记住三十六计第几计,名称,内容。 第一套:胜战计,即一到六计。 第一计 瞒天过海 方法:由第一计的一,可以联...

  • 微小说|无奈的阴谋

    阴谋者,秘计,诡计也,方法和目的是用谎言诱导别人犯错误,但本故事所讲的阴谋,却是个无奈之举。 ...

  • 评书连载:《闲话三国》(671)

    周瑜想,你用此计?我从来没有看见你用过计,你也会用计?便问:“尔用此计便怎样?” “理当派遣一将,带兵...

  • 第3期PPT演讲力训练营毕业复盘

    第三期的PPT训练营又学到了四计:创业计、总裁计、道具计、台风计。回顾一下: 创业计:用一句话介绍公司产品...

网友评论

      本文标题:用BitmapFactory.decodeStream()方法计

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