图片解码之后生成Bitmap,Bitmap对象占用的内存特别大,这种情况特别容易造成内存抖动,甚至发生OOM。解决这个问题除了图片压缩之外,还需要合理的控制图片的缓存。
缓存有三级,分别是:网络、磁盘、内存,即三级缓存。
(1)三级缓存
1、定义
网络缓存:从网络读取图片,ImageView可以将网络图片直接显示出来;
磁盘缓存:从本地读取图片,ImageView可以将本地图片直接显示出来;
内存缓存:如果Bitmap存在内存中,ImageView可以直接将Bitmap显示出来;
2、加工
如果直接将网络图片显示在屏幕上,很容易发生OOM,因为网络图片的大小不可控制,谁也不知道网络图片的大小是多少。
所以,首先需要将图片下载到本地并压缩,然后将压缩后的图片解码成Bitmap。
3、策略
先从内存中获取图片,如果没有就从磁盘中取,如果磁盘中依然没有,会从网络中获取。
(2)一些概念
1、软引用和弱引用
为了方便回收Bitmap对象,最好将Bitmap对象用软引用或者弱引用修饰;
软引用:当内存不够的时候才会被GC回收;
弱引用:当GC执行的时候立即被回收;
根据软弱引用的特性,推荐使用`弱引用`。
2、回收
Bitmap对象可以使用以下方法回收:
bitmap.recycle()
然而,这个方法特别容易造成如下异常:
image.png
顾名思义,已经被回收的Bitmap对象再次被使用了。所以,使用该方法要非常谨慎。
3、复用
Bitmap所属的内存块是可以复用的,`BitmapFactory.Options`的`inBitmap`属性可以存储Bitmap对象,
当`BitmapFactory.Options`的`inMutable`属性为true时,则支持复用,所以`inMutable`和`inBitmap`会一起使用。
完成的代码如下:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.kongque, options);
options.inBitmap = bitmap;
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ceshi, options);
`inMutable `的赋值必须在`decodeXXX`之前,生成Bitmap之后,将Bitmap赋值给`inBitmap`。
4、内存缓存(LruCache)
LruCache是Android自带的内存缓存类,`LruCache`采用最近最少使用算法,将最近最少使用的缓存清除。
(3)手写四级缓存架构(简化版)
平时我们所说的三级缓存是指:内存缓存 + 磁盘缓存 + 网络缓存。
四级缓存就是:内存缓存 + 复用池 + 磁盘缓存 + 网络缓存。
为此,我手写了一个简单的加载网络图片的框架。
地址是:https://github.com/NoBugException/ImageCache
注意:
Demo只适用于学习和总结,如果用在项目中使用并不能保证稳定,因为Demo并没有经过精细的测试过。
网友评论