什么是图片的三级缓存?
所以我们可知,读取图片优先从内存中读取,内存中没有就去读本地,本地没有才去网络上下载。
简单说下网络缓存
我们可以使用Android原生的AsyncTask<Params, Progress, Result>,它是 线程池 + handler的封装。它带泛型,自己维护了一个线程池。
* 参数1: 异步处理传入的参数(与doInBackground一致)
* 参数2: 更新进度的参数(与onProgressUpdate一致)
* 参数3: 异步处理返回结果,界面更新的参数(与onPostExecute参数一致,与doInBackground返回值一致)
写个类集成AsyncTask<Params, Progress, Result>,重写doInBackground方法,这方法是在子线程中在此方法中写下载图片的异步处理代码即可。还有onPreExecute(主线程,预加载时执行),onProgressUpdate(主线程,进度更新在此处理),onPostExecute(主线程,更新主界面)
本地缓存无非就是将图片保存到本地(即手机外存)了。
Environment.getExternalStorageDirectory().getAbsolutePath() + "/你程序缓存目录名"
这里稍微提一下的是Bitmap类有一个compress(format, quality, stream)方法,将图片压缩到本地,参数1:图片压缩格式 参数2:质量0-100 参数3:输出流
接下来就是本文的重点内存缓存了。
为什么是重点呢,因为众所周知,Android下处理图片不小心很容易出现oom内存溢出。这里将介绍一些方法来将图片保存到内存当中。
首先是普及一个知识(大牛可跳过)
Java引用是有强,软,弱,虚4个等级之分的。
-强引用 Person p = new Person()
-软引用 SoftReference 较弱
-弱引用 WeakReference 其次弱
-虚引用 PhantomReference 引用最弱
Java的GC是只会去回收那些没有人要的对象,是不会去回收强引用的。所以在早前内存缓存所用到的技术都是SoftReference 软引用。
我们可以new一个这样键值对的HashMap<String, SoftReference<Bitmap>>,这样你添加进去的bitmap图片对象就是软引用,这样GC在内存不够时就会去回收这些对象,从而避免内存溢出。
但是自 Android 2.3(API LEVEL 9)之后,GC有了一些改变,它会更加容易的去回收这些软引用,造成的结果是用软引用来实现图片内存缓存基本失效咯,因为你软引用的图片加载到内存不一会儿也会被GC回收(可自行去看google官方文档说明)。所以关于软引用实现图片缓存的方法就里就不多提了。
google自己就推出了一个解决方案。有一个类叫做LruCache。(LRU算法:Least Recently Used 近期最少使用算法)
首先科普一下,Android默认给每一个app分配的内存大约是16M,这个根据真机可能有所浮动。
LruCache内部的实现原理其实就是一个LinkedHashMap,同时它有一个全局变量size,由你自己设定,这样它自己会维护这个hashmap。内部它会计算每一个value的大小size,如果它发现内存要满了,它就会移除最早的一个value。直到内存够了为止。就好像家里的洗手池,上面会有一个小口,水要是快满了就会从小口里流走,这样永远也不会造成溢出。
说了大概的实现原理,接下来就说说具体该怎么用了,不多说,直接上个Demo
public class MemoryCacheUtils { private LruCache<String, Bitmap> mLruUtils; public MemoryCacheUtils(){ // 获得虚拟机分配的内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); mLruUtils = new LruCache<String, Bitmap>(maxMemory/8){ @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } }; } public Bitmap getBitmapFromMemory(String url){ Bitmap bitmap = mLruUtils.get(url); return bitmap; } public void setBitmapToMemory(String url, Bitmap bitmap){ mLruUtils.put(url, bitmap); }
注意一定要重写LruCache类的sizeOf方法,因为它默认返回1个字节,你得根据你自己的需求来计算,上图代码是计算每一张Bitmap图片的大小。
以上就是我所学到关于Android图片三级缓存的知识,虽然这个可以实现图片的内存缓存,还是还是可能造成OOM的情况发生,所以建议大家还是使用那优秀的BitmapUtils,但是为什么还说这些干嘛,因为BitmapUtils都已经给我们封装好了,原理我们还是得知道的,不然怎么在面试官面前装个高逼格呢?
如有说错不妥之处,请指正。