前言

我们要说点什么:

1.我们应该怎么加载一个大图片,从而避免OOM(我喜欢stackoverflow.com的名字)

2.我们是否应该鄙视:setbackgroundresource等直接通过一个id构建bitmap/drawable的方法

3.一些参考资料

正文

加载那个大图片

你的图片有多大,在我看来,一张40K+的图片,已经被称为大图片了

当你的程序,通过view.setbackgroundxxx来频繁的(100ms一张图片,或者,更短的ms)更换图片时(或者,你采用surfaceview的style),上述的40K+已经非常的大了

你应该选择什么API来显示你的图片:

bitmapdrawable,而不是setbackgroundresource(int id)

为什么:通过一个id来获取一个bitmap/drawable时,android系统会对该资源进行缓存,从而下次访问迅速响应,但是,它只缓存,不释放,再多的memory也不够用,进而OOM

bitmapdrawable的创建过程很节省时间吗?:

我曾经做过一个实验,在无bitmapfactory.options的时候,反复的加载一个40K+的图片1000次,算的其平均加载一张图片的时间为:68ms

options.inSampleSize

针对于上面的例子,当你选择设置了options.inSampleSize = 2时(width和height均为原来的1/2),你会得到平均30ms左右的加载时间

但是,inSampleSize会使得图片的尺寸缩小(如果view.lp.width/height为wrap_content),会使得图片变得模糊(如果view.lp.width/height被限定成xxdp,这也包含了match_parent)

但是,它是有用的:

一个场景:你已经算的,你的view只有50px*50px的大小,而对应的image的分辨率却是720px*1280px

那么,你应该确定options.inSampleSize,来减少加载时间,甚至避免oom

下面,给出一个最佳实践:

public static final BitmapFactory.Options getBitmapOptions(BitmapFactory.Options... option) {BitmapFactory.Options options = null;if (option == null || option.length == 0) {options = new BitmapFactory.Options();} else {options = option[0];}options.inPurgeable = true;options.inInputShareable = true;// options.inDither = true;// options.inScaled = false;options.inPreferredConfig = Bitmap.Config.RGB_565;return options;
}/*** 在加载asset图片时,考虑opt.inSampleSize:比较 img.width/height 和 width/height* * @param path* @param am* @param width*            要求的width* @param height*            要求的height* @return*/
public static final Bitmap getBitmapConsideringSize(String path,AssetManager am, int width, int height) {InputStream is = null;Bitmap bitmap = null;try {is = am.open(path);BitmapFactory.Options opt = new Options();opt.inJustDecodeBounds = true;BitmapFactory.decodeStream(is, null, opt);int widthRatio = (int) Math.ceil(opt.outWidth / (float) width);int heightRatio = (int) Math.ceil(opt.outHeight / (float) height);opt = getBitmapOptions();if (widthRatio > 1 && heightRatio > 1) {opt.inSampleSize = widthRatio > heightRatio ? widthRatio: heightRatio;}bitmap = BitmapFactory.decodeStream(is, null, opt);} catch (Exception e) {e.printStackTrace();} finally {closeStream(is);}return bitmap;
}

通过上述方法,每次加载40K+的图片,平均只需要26ms,且没有改变图像的尺寸(别被骗了,你的图片规格有可能降低了:RGB_565,但是,还好)

看看decodestream

转:

使用view.setBackgroundResource,imageview.setImageResource,bitmapFactory.decodeResource这样的方法来设置一张大图片的时候,
这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。
如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常
注意:decodeStream直接拿的图片来读取字节码了,不会根据机器的各种分辨率来自动适应

使用缓存LruCache

为什么用:使用缓存,可以让我们下次访问一个元素 的消耗时间 变短
lru: Least Recently Used
cache: 缓存
如何访问:我们放入item<key,value>到这个cache中,我们根据key来去取value(注意:value有可能为null,下面说,为什么)
有什么用:
我们在源源不断的往cache里面放入item(而item本身可能是耗内存的,比如<String, Bitmap>),
我们不在意:是否因为生成了足够多的item,而占据了大量的内存,从而导致oom,
为什么:cache在帮我们维护内存,它知道:在我们即将放入一个item时,有可能会导致oom,则,它释放掉lru item(s)
注意什么:当我们根据key来获取value时,value有可能为null,那么,需要自行构建value,(并建议:将<key,value>放入到cache中)
参考:
https://developer.android.com/reference/android/util/LruCache.html
https://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
http://stackoverflow.com/questions/12716574/bitmap-recycle-with-largeheap-enabled

别让你的程序卡掉,或者,抛出异常

作为一个单独的小结,我理解,上述问题是多么的重要,以及,令人抓狂

你可以试试每隔60ms来播放1万张40K+图片,并且按照上述方法来进行展示

但是,依然,程序能挂掉,或者,屏幕已经全黑了(你会很确定,你的程序没有死掉,但是,你看到的一切全黑了)

你查看logcat,你会发现:imageref_ashmem create failed <(null)>

可以google,或者stackoverflow,它会告诉你,你需要释放bitmap

你可能会反问,都不会再OOM了,为什么还要释放bitmap,答案,很简单,因为黑屏,因为异常(开玩笑的,如果你知道更确认的原因,请告诉我,请尽量使用通俗易懂的语言,3x)

如何释放一个bitmap:bitmap.recycle()

bitmap会立刻释放吗:不会,但是会在某个时刻被释放

它会立刻引发GC吗:不会(说到这里,如果在你的程序里,频繁的调用gc,或者被动的被调用gc(如:频繁的调用setbackgroundresource,且每次都是个大图片),那么你将有幸看到你的程序离迟钝只有一步之遥了,所以,请不要这样做,因为,它只会让性能更差,你可以实验一下)

它会引发什么样的问题:你可能有机会看到这样一个异常:{你引用了一个已经被recycled的bitmap,然后程序就这样挂了},所以,请你考虑应该进行释放操作的时机,给一个参考:你在显示当前图片的时候,也许,你愿意将之前的图片给释放掉

我们该鄙视诸如setbackgroundresource此类吗

的确,setbackgroundresource让人抓狂:它缓存了太多东西,导致OOM

但是,它的存在是为了它的另外一面:当下次访问该图片的时候,能快速响应

接下来的一个问题,下次访问是在什么时候,停100ms再访问这个图片算很长吗?

不幸的是,是的,100ms再访问,会显的很长

当你在编写一个撞球的游戏,每100ms刷新一次屏幕,是那么的漫长,这时,你巴不得刚设置完view的img后,就立刻开始下一次view的img设置(因为android的刷新是有时间的,所以,这样做,是有意义的)(啊,这个球很快,这一秒还在这,下一秒已经在那了,太快了,瞬间转移,也许,你也认为100ms一帧是漫长的)

从bitmapdrawable中实验来看,图片加载的时间为20ms,那么,这个时间很快吗?有直接从缓存里面取来的快吗?

所以,我们不应该鄙视

一些参考资料

google上有很多的处理OOM的资料,在此,我贴出一些:

https://developer.android.com/training/displaying-bitmaps/index.html

http://blog.sina.com.cn/s/blog_5de73d0b010117ix.html

http://www.cnblogs.com/siyiganshou/

http://blog.csdn.net/imyfriend/article/details/8039767

如何加载 那个大图片相关推荐

  1. VUE项目中图片加载过大处理方式-渐进式方式-懒加载方式--附源码

    解决有两步: 1.采用渐进式加载:原图未加载完时显示比它内存小的模糊图: 2.采用懒加载:只加载可视区域的图片,即滚动到可视区域时再加载图片 vue-lazyload-img:VUE图片懒加载插件 v ...

  2. Android加载/处理超大图片神器!SubsamplingScaleImageView(subsampling-scale-image-view)【系列1】...

     Android加载/处理超大图片神器!SubsamplingScaleImageView(subsampling-scale-image-view)[系列1] Android在加载或者处理超大巨 ...

  3. 更有效的加载较大的Bitmap

    译文出自谷歌安卓官方:https://developer.android.com/training/displaying-bitmaps/load-bitmap.html#read-bitmap 图片 ...

  4. gif android 点击 加载,android 加载显示gif图片的解决方案

    使用方法: 1-把GifView.jar加入你的项目. 2-在xml中配置GifView的基本属性,GifView继承自View类,和Button.ImageView一样是一个UI控件.如: andr ...

  5. android 加载网络bitmap图片 oom 简书_Android常见问题--ImageView加载图片OOM

    开发中给ImageView加载一个高质量图片时,APP抛出了"Canvas: trying to draw too large(840253440bytes) bitmap."的异 ...

  6. jquery 当页面图片加载之后_图片的懒加载和预加载

    一.懒加载 [1.1]什么是懒加载? 懒加载也就是延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式.当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1 ...

  7. ios wkweb设置图片_ios·WKWebView\UIWebView加载HTMLString,实现图片懒加载

    背景: 项目中开发商品类型数据,数据可变性较大,所以商品详情数据存在文案和图片富文本显示,后台返回了html格式的数据供前端展示. 如果用webView直接显示的话,需要等html内容完全展示才能获取 ...

  8. Android加载/处理超大图片神器!SubsamplingScaleImageView(subsampling-scale-image-view)【系列1】

     Android加载/处理超大图片神器!SubsamplingScaleImageView(subsampling-scale-image-view)[系列1] Android在加载或者处理超大巨 ...

  9. 使用Glide加载、缓存图片、Gif、解决背景出现浅绿色、GlideModules冲突

    之前一直使用Volley ImageLoader.或者Picasso,无意间发现Glide,觉得真的是棒棒的. 1.和其他的一样在Module的build.gradle中添加依赖 compile 'c ...

最新文章

  1. php 怎么支持中文图片显示,给图片添加水印(支持中文)并生成缩略图_php
  2. 图片上两点之间的距离和两组图片之间的差异的关系
  3. 数据中台、标签、数据资产相关的15个名词解释
  4. 淘宝NPM镜像、cnmp
  5. ID3决策树中连续值的处理+周志华《機器學習》图4.8和图4.10绘制
  6. unity3d Json解析工具类
  7. 【Spark】Spark-空RDD判断与处理
  8. 面试pythone_叮!你需要的Python面试指南以送到!
  9. 机器学习(5)——决策树(预测隐形眼镜类型)
  10. duilib加载xml以及资源文件的路径问题
  11. c语言函数 参数,C语言函数的调用与参数
  12. 【Python】与或非的符号表示
  13. K8s 亲和性和非亲和性(Affinity)
  14. c语言程序设计第六章习题答案,C语言程序设计(第2版) 刘克威,张凌晓著 习题答案-第六章...
  15. SSL_WRITE在断网时的表现
  16. 人工智能行业每日必读(02·03)
  17. 多块英伟达K80显卡linux安装,ubuntu14.04下NVIDIA Tesla K80 、GTX1080顯卡驅動以及Tensorflow、Python的安裝教程...
  18. 开发者涨薪指南:提升软、硬实力
  19. 简单学JAVA-Java学习方法-JavaSE阶段
  20. matlab grab cut,matlabGrabCutS graph 算法, 编写,可以运 能直观看到结果。 272万源代码下载- www.pudn.com...

热门文章

  1. Chrome网页编码显示乱码
  2. 【GPU精粹与Shader编程】 七 一篇文章读完 GPU Gems 3
  3. 图文并茂认识计算机网络
  4. HDU-2549 壮志难酬
  5. transformer学习之多头注意力机制
  6. 【小猪佩奇漫画】| 复杂度分析原来那么简单!
  7. gb和gib的区别_GB 和 GiB 的区别
  8. Android L添加kk版的OOBE开机向导
  9. 容天服务器4450系统密码,金铂gob q7-f手机忘记开机密码怎么办
  10. 基于Python实现的桌面图书管理系统