使用LruCache和DiskLruCache实现内存磁盘二级图片缓存

关于LruCache内存缓存管理类

       android.util.LruCache<K, V>是一个Android官方提供的内存缓存管理类,它是在Android 3.1(代号 Honeycomb MR1)引入的。LruCache可以在创建时定义缓存的最大长度,而且还可以通过覆写sizeof()方法改变每个缓存条目计算大小的方式。由于android.util.LruCache是在Android 3.1版本才引入的API,所以只能在Android 3.1及更高版本上使用。但是为了兼容Android 3.1以下版本的设备,我们需要在工程中引用android-support-v4.jar库(新版本的Eclipse在新建工程的时候就自动引用了)。

       我们可以通过LruCache类来进行图片的内存缓存管理

关于DiskLruCache磁盘缓存管理类

       Google提供了一套硬盘缓存的解决方案:DiskLruCache(Google官方编写,但获得官方认证)。像官方的LruCache一样,DiskLruCache不但提供了缓存文件的写入、读取、删除基本功能,还提供了定义缓存大小的方法,同时还具备了缓存文件绑定版本号以及设定一个key对应的文件数等功能。

       我们可以通过DiskLruCache类来进行图片的磁盘缓存管理。使用之前需要在工程中引用DiskLruCachejar包。

       点击这里下载DiskLruCache.jar

一、内存磁盘两级缓存的架构设计如下:


二、工作流程如下:

1、先调用内存缓存管理获取内存缓存中图片显示,结果为空则进行下一步;

2、调用磁盘缓存管理类获取磁盘缓存中图片显示,如果有则显示,并将其保存到内存缓存中,如果为空则进行下一步;

3、从网络中请求图片,将请求结果显示,并保存到内存缓存和磁盘缓存中。

三、实现内存缓存管理类

实现一个名为ImageLruCache类,用来管理图片的内存缓存:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import android.content.Context;
import android.os.Build;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.graphics.Bitmap;

public class ImageLruCache{
	
	public static final String TAG = ImageLruCache.class.getSimpleName();
	
	private LruCache<String, Bitmap> mMemoryCache;
	private ImageDiskLruCache mImageDiskLruCache;
	
	//构造函数
	public ImageLruCache(Context context){

		// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
	    // LruCache通过构造函数传入缓存值,以KB为单位。
	    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
	    // 使用最大可用内存值的1/8作为缓存的大小。
	    int cacheSize = maxMemory / 8;
	    Log.i(TAG, "The Size of MemoryCache is " + cacheSize/1024 + " MB");
	    
	    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
	        @Override
	        protected int sizeOf(String key, Bitmap bitmap) {
	            // 重写此方法来衡量每张图片的大小,默认返回图片数量。 
	        	if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1 ){
		            return bitmap.getByteCount() / 1024;
	        	}else{
	        		return bitmap.getRowBytes()*bitmap.getHeight() / 1024;
	        	}
	        }
	        
	    };
	    mImageDiskLruCache = new ImageDiskLruCache(context);
	}
	
	//添加图片进缓存
	@Override
	public void putBitmap(final String url, final Bitmap bitmap) {
		final String key = hashKeyForLruCache(url);
		
		mMemoryCache.put(key, bitmap);
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				mImageDiskLruCache.addBitmapToDiskCache(url, bitmap);
			}
		}).start();
		return;
	}
	
	//从缓存中取出图片
	@Override
	public Bitmap getBitmap(String url) {
		String key = hashKeyForLruCache(url);
		Bitmap bm = mMemoryCache.get(key);

		if(bm != null){
			return bm;
		}
		else
		{	
			bm = mImageDiskLruCache.getBitmapFromDiskCache(url);
			if (bm != null) {
				mMemoryCache.put(key, bm);
			}
			return bm;
		}
	}
	
	
	//删除缓存文件
	public boolean removeBitmap(String url) {
		String key = hashKeyForLruCache(url);
		mMemoryCache.remove(key);
		return mImageDiskLruCache.removeImageFromDiskCache(url);
	}
	
	
	//将key进行MD5编码
	public String hashKeyForLruCache(String key) {
		String cacheKey;
		try {
			final MessageDigest mDigest = MessageDigest.getInstance("MD5");
			mDigest.update(key.getBytes());
			cacheKey = bytesToHexString(mDigest.digest());
		} catch (NoSuchAlgorithmException e) {
			cacheKey = String.valueOf(key.hashCode());
		}
		return cacheKey;
	}

	private String bytesToHexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < bytes.length; i++) {
			String hex = Integer.toHexString(0xFF & bytes[i]);
			if (hex.length() == 1) {
				sb.append('0');
			}
			sb.append(hex);
		}
		return sb.toString();
	}
}

1、类中将内存缓存的大小设置为App最大可用内存的1/8;

2、提供putBitmap、getBitmap、removeBitmap三个方法;

3、将图片的键值进行MD5转换后保存。

 四、实现磁盘缓存缓存管理类

实现一个名为ImageDiskLruCache类,用来管理图片的磁盘缓存:

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import com.jakewharton.disklrucache.DiskLruCache;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

public class ImageDiskLruCache {
	
	public static final String TAG = ImageDiskLruCache.class.getSimpleName();
	
	private DiskLruCache mDiskLruCache; 
	private int mDiskCacheSize = 1024 * 1024 * 100; // 100MB
	
	//初始化函数
	ImageDiskLruCache(Context context){
	    try {

	    	File cacheDir = context.getCacheDir();
			File imageCacheDir = new File(cacheDir + "/image");
			//如果文件夹不存在则创建
			if (!imageCacheDir.exists()) {
				imageCacheDir.mkdirs();
			}

			//第一个参数指定的是数据的缓存地址,第二个参数指定当前应用程序的版本号,
			//第三个参数指定同一个key可以对应多少个缓存文件,基本都是传1,第四个参数指定最多可以缓存多少字节的数据
	    	mDiskLruCache = DiskLruCache.open(imageCacheDir, getAppVersion(context), 1, mDiskCacheSize);
		}
	    catch (IOException e) {
			Log.i(TAG, "fail to open cache");
		}

	}
	
	//获取应用的版本号
	public int getAppVersion(Context context) {
		try {
			PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
			return info.versionCode;
			}
		catch (NameNotFoundException e){
			e.printStackTrace();
			}
		return 1;
	}
	
	
	//添加图片到缓存
	public void addBitmapToDiskCache(final String data, final Bitmap bitmap) {  
        if (data == null || bitmap == null) {  
            return;  
        }  

        if (mDiskLruCache != null) {  
            final String key = hashKeyForDisk(data);  
            OutputStream out = null;  
            try {  
                final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);  
                if (snapshot == null) {  
                    final DiskLruCache.Editor editor = mDiskLruCache.edit(key);  
                    if (editor != null) {  
                        out = editor.newOutputStream(0);  
                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);  
                        editor.commit();  
                        out.close();  
                        mDiskLruCache.flush();
                    }  
                } else {  
                    snapshot.getInputStream(0).close();  
                }  
            } catch (final IOException e) {
            	
            } finally {  
                try {  
                    if (out != null) {  
                        out.close();  
                        out = null;  
                    }  
                } catch (final IOException e) {  
                } catch (final IllegalStateException e) {  
                }  
            }  
        }  
    } 
	
	
	//从缓存中取出图片
	public final Bitmap getBitmapFromDiskCache(final String data) {  
        if (data == null) {  
            return null;  
        }  
  
        final String key = hashKeyForDisk(data);//md5生成key  
        if (mDiskLruCache != null) {  
            InputStream inputStream = null;  
            try {  
                final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);  
                if (snapshot != null) {  
                    inputStream = snapshot.getInputStream(0);  
                    if (inputStream != null) {  
                        final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);  
                        if (bitmap != null) {  
                            return bitmap;  
                        }  
                    }  
                }  
            } catch (final IOException e) {  
 
            } finally {  
                try {  
                    if (inputStream != null) {  
                        inputStream.close();  
                    }  
                } catch (final IOException e) {  
                }  
            }  
        }  
        return null;  
    }
	
	//删除缓存文件
	public boolean removeImageFromDiskCache(final String data) { 
		if (data == null) {  
            return false;  
        }
		
		final String key = hashKeyForDisk(data);//md5生成key  
        if (mDiskLruCache != null) { 
        	try {
        		boolean remove =  mDiskLruCache.remove(key);
				return remove;
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}
        }
		return false;
	}
	
	//将key进行MD5编码
	public String hashKeyForDisk(String key) {
		String cacheKey;
		try {
			final MessageDigest mDigest = MessageDigest.getInstance("MD5");
			mDigest.update(key.getBytes());
			cacheKey = bytesToHexString(mDigest.digest());
		} catch (NoSuchAlgorithmException e) {
			cacheKey = String.valueOf(key.hashCode());
		}
		return cacheKey;
	}

	private String bytesToHexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < bytes.length; i++) {
			String hex = Integer.toHexString(0xFF & bytes[i]);
			if (hex.length() == 1) {
				sb.append('0');
			}
			sb.append(hex);
		}
		return sb.toString();
	}
}

1、引用了第三方库DiskLruCache,需要下载DiskLruCache.jar并引入到功能中, 点此下载

2、这里将磁盘缓存的大小设置为100M;

3、提供addBitmapToDiskCache、getBitmapFromDiskCache、removeBitmapFromDiskCache三个方法;

4、将图片的键值进行MD5转换后保存。

 五、二级缓存的使用

直接调用ImageLruCache的方法就可以实现了二级缓存的存取删除功能。

 

参考:

http://www.bdqn.cn/news/201307/10432.shtml

http://blog.csdn.net/guolin_blog/article/details/28863651

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值