Android图片之三级缓存(着重讲内存缓存)

在现在第三方开源框架xUtils中BitmapUtils大行其道,它的确是一款很好的第三方图片开源框架,但是在使用BitmapUtils时,Android下图片的三级缓存,我们还是得知道其中原理的。如果面试的时候能与面试官答上一二,会为你加分不少。

Android图片之三级缓存(着重讲内存缓存)_第1张图片       

什么是图片的三级缓存?                                               

  1. 内存缓存      速度快  +  无流量 
  2. 本地缓存      速度稍快  +  无流量
  3. 网络缓存      速度慢  +  耗流量     



所以我们可知,读取图片优先从内存中读取,内存中没有就去读本地,本地没有才去网络上下载。


简单说下网络缓存

我们可以使用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都已经给我们封装好了,原理我们还是得知道的,不然怎么在面试官面前装个高逼格呢?


如有说错不妥之处,请指正。

你可能感兴趣的:(android,图片,内存,缓存)