通过DiskLruCache以及LruCache来构建自己项目的图片缓存框架

前言:

众所周知,对于手机项目而言,图片缓存框架是必不可少的,这样不仅能优化项目的性能,同时也能提高用户体验。git上也有许多开元的图片缓存框架,有很多可以选择,我这仅仅只是教你如何编写一份属于自己的图片缓存框架,这也是我早期之前在其中一个项目中编写的。(仅仅只支持从网络上获取base64转码过来的图片)。
图片缓存基本上,都是通过DiskLruCache以及LruCache来实现的,一个是硬盘缓存,以及一个内存缓存。这两个我就不详细解释了,网上基本上有很多介绍资料。先上一个DiskLruCache下载链接:DiskLruCache 下载。
这是我之前用过的DiskLruCache,接下来就是介绍如何构建我们的图片缓存框架了。
基本上的思路是这样的:

1.通过单例模式来构建我们的框架类
2.LruCache和DiskLruCache的内存大小设置
3.优化图片的显示,通过Imageview的宽高来压缩我们的图片
4.处理以上3个点基本上就能构建一个简单的图片缓存框架了,当然具体可以根据自己项目中的具体需求来添加内容,比如增加线程池处理,或者增加图片的处理,或者说根据图片的存储来定时清除内存缓存的图片等等。
代码中基本上都有注释,这里就不详细解释了。项目中的具体处理我就没贴进去了 仅仅只是对于图片缓存的处理。
package cn.com.hnisi.fj.ydzfba.module.ydjcq.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cn.com.hnisi.fj.ydzfba.module.ydjcq.utils.DiskLruCache.Snapshot;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaMuxer.OutputFormat;
import android.os.Environment;
import android.support.v4.util.LruCache;
import android.util.Base64;
import android.util.Log;


/**
 * imagePath是唯一的标识
 * */
public class ImageCache {
	private FileOutputStream fos;
	public DiskLruCache mDiskCache;
	public LruCache mMemoryCache;

	private ImageCache() {

	}
	
	public static ImageCache getInstance() {
		return ImageCacheHolder.imageCache;
	}

	public static class ImageCacheHolder {
		public static final ImageCache imageCache = new ImageCache();
	}
	
	
	public void initCache(Context context) {
		/** 初始化LruCache 获取内存的1/8*/
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int cacheSize = maxMemory / 8;

		mMemoryCache = new LruCache(cacheSize) {
			@Override
			protected int sizeOf(String key, Bitmap bitmap) {
				// TODO Auto-generated method stub
				return bitmap.getByteCount();
			}
		};

		/** 初始化DiskLruCache */
		try {
			File cacheDir = getDiskCacheDir(context, "xcdc");
			if (!cacheDir.exists()) {
				cacheDir.mkdirs();
			}
			mDiskCache = DiskLruCache.open(cacheDir, 1, 1, 50 * 1024 * 1024);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/** 内存缓存的获取 */
	public Bitmap getBitmapFromMemoryCache(String imagePath) {
		return mMemoryCache.get(imagePath);
	}

	/** 把图片放到内存缓存中 */
	public void addBitmapToMemoryCache(String imagePath, Bitmap bitmap) {
		if (mMemoryCache.get(imagePath) == null) {
			mMemoryCache.put(imagePath, bitmap);
		}
	}

	/** 本地缓存,通过diskLruCache把图片放到本地磁盘中 
	 * @throws IOException */
	public void addBitmapByDiskLruCache(Bitmap bitmap, String imagePath, int reqWidth, int reqHeight){
		Snapshot snapshot = null;
		BufferedInputStream in = null;
		BufferedOutputStream out = null;
		String key = imagePath;
		// 查找对应缓存的key
		try {
			snapshot = mDiskCache.get(key);
			if (snapshot == null) {
				// 如何没有找到对应的缓存,则把图片添加到缓存中(DiskLruCache))
				DiskLruCache.Editor editor = mDiskCache.edit(key);
				if (editor != null) {
					if (bitmap != null) {
						// 获取editor的outputStream
						OutputStream outputStream = editor.newOutputStream(0);
						// bitmap转化为inputStream
						ByteArrayOutputStream baos = new ByteArrayOutputStream();
						bitmap.compress(Bitmap.CompressFormat.PNG, 30, baos);
						InputStream is = new ByteArrayInputStream(baos.toByteArray());
						in = new BufferedInputStream(is, 8 * 1024);
						out = new BufferedOutputStream(outputStream, 8 * 1024);
						int b;
						while ((b = in.read()) != -1) {
							out.write(b);
						}
						editor.commit();

					} else {
						editor.abort();
					}
					mDiskCache.flush();
				}

			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				if (in != null) {
					in.close();
				}

				if (out != null) {
					out.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}
	
	//图片是否在DiskLruCache中
	public boolean isInDiskLruCache(String imagePath){
		Snapshot snapshot = null;
		boolean flag = false;
		try {
			snapshot = mDiskCache.get(imagePath);
			if(snapshot == null){
				flag =  false;
			}else{
				flag =  true;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return flag;
	}
	
	//从DiskLruCache中移除旧缓存
	public void removeImageFromDiskLruCache(String imagePath){
		try {
			mDiskCache.remove(imagePath);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**通过本地缓存获取图片
	 * @throws IOException */
	public Bitmap getBitmapFromDiskLruCache(String imagePath, int reqWidth, int reqHeight){
		if(mDiskCache ==null){
			return null;
		}
		
		Bitmap bitmap = null;
		DiskLruCache.Snapshot snapshot;
		try {
			snapshot = mDiskCache.get(imagePath);
			if(snapshot != null){
				FileInputStream fis = (FileInputStream) snapshot.getInputStream(0);
				FileDescriptor fileDescriptor = fis.getFD();
				bitmap = decodeSampleBitmapFromFileDescriptor(fileDescriptor, reqWidth, reqHeight);
				if(bitmap!=null){
					addBitmapToMemoryCache(imagePath, bitmap);
				}
			}
			
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return bitmap;
	}

	/**
	 * File文件中的bitmap的获取,获取后的bitmap是经过压缩的 内存缓存
	 */
	public Bitmap decodeSampleBitmapFromFile(String filePath, int reqWidth,
			int reqHeight) {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(filePath, options);

		options.inSampleSize = calculateInSampleSize(options, reqWidth,
				reqHeight);
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFile(filePath, options);
	}

	/**
	 * 通过DiskLruCache,的FileInputStream对象来获取Bitmap 本地缓存
	 */
	public Bitmap decodeSampleBitmapFromFileDescriptor(FileDescriptor fd,
			int reqWidth, int reqHeight) {
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFileDescriptor(fd, null, options);

		options.inSampleSize = calculateInSampleSize(options, reqWidth,
				reqHeight);
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFileDescriptor(fd, null, options);

	}

	/**
	 * 计算bitmap的InSimpleSize 内存缓存
	 */
	public int calculateInSampleSize(BitmapFactory.Options options,
			int reqWidth, int reqHeight) {
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqWidth || width > reqHeight) {
			final int halfWidth = height / 2;
			final int halfHeight = width / 2;
			while ((halfHeight / inSampleSize) >= reqHeight
					&& (halfWidth / inSampleSize) >= reqWidth) {
				inSampleSize *= 2;
			}
		}
		return inSampleSize;
	}

	/** 获取file,得到缓存路径,本地缓存 */
	public File getDiskCacheDir(Context context, String fileName) {
		String cachePath;
		if (Environment.MEDIA_MOUNTED.equals(Environment
				.getExternalStorageState())
				|| !Environment.isExternalStorageRemovable()) {
			cachePath = context.getExternalCacheDir().getPath();
		} else {
			cachePath = context.getCacheDir().getPath();
		}

		return new File(cachePath + File.separator + fileName);
	}

	/** 清除内存缓存 */
	public static void clearSARYCache(String dir) {
		File file = new File(dir);
		if (!file.exists()) {
			file.mkdirs();
		}
		File[] files = file.listFiles();
		for (File mFile : files) {
			mFile.delete();
		}

	}

	public static Bitmap base64ToBitmap(String base64String) {
		byte[] bytes = Base64.decode(base64String, Base64.DEFAULT);
		Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
		return bitmap;
	}
}


当然,你也可以把这个类的功能拆分,把图片的压缩,和缓存的创建以及put/get放入到不同的类中,这样就减少了代码的耦合度,同时也方便以后扩展。由于这是早期的代码,并且也只有base64形式的图片数据,所以也就没对这个框架进行重构了。

你可能感兴趣的:(android)