Android结合volley的netWorkImageview实现图片文件缓存

在写Android应用程序时经常会用到图片缓存,对于网络请求使用Android平台上的网络通信库Volley,能使网络通信更快,更简单,更健壮,而且Volley特别适合数据量不大但是通信频繁的场景,所以可以使用volley来请求网络图片。接下来就将本人在一个项目中的图片缓存模块拿出来跟大家分享,欢迎批评指正。

/**
 * @author 
 * @date 2015/4/14 
 * 利用文件缓存图片
 */

public class ImageFileCacheUtils {
	private static final String CHCHEDIR = "ImageChace";//缓存目录
	private static final String WHOLESALE_CONV = ".cache";//缓存文件后缀名
	private static final int MB = 1024 * 1024;
	private static final int CACHE_SIZE = 80;//缓存最大容量(超过就会利用lru算法删除最近最少使用的缓存文件)
	private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 100;//缓存所需SD卡所剩的最小容量
	
	private static ImageFileCacheUtils instance = null; 
	//单例模式
	public static ImageFileCacheUtils getInstance(){
		if (instance == null) {
			synchronized (ImageFileCacheUtils.class) {
				if (instance == null) {
					instance = new ImageFileCacheUtils();
				}
			}
		}
		return instance;
	}
	
	public ImageFileCacheUtils(){
		removeCache(getDirectory());
	}
	
	/**
	 * 从文件缓存中获取图片
	 * @param url
	 * @return
	 */
	public Bitmap getImage(final String url){
		final String path = getDirectory() + "/" +convertUrlToFileName(url);
		File file = new File(path);
		if(file.exists()){
			Bitmap bitmap = BitmapFactory.decodeFile(path);
			if(bitmap == null){
				file.delete();
				return null;
			}else {
				updateFileTime(path);//更新文件最新访问时间
				return bitmap;
			}
		}else {
			return null;
		}
	}
	
	/**
	 * 获得缓存目录
	 * @return
	 */
	private String getDirectory() {
		String dir = getSDPath() + "/" + CHCHEDIR;
		return dir;
	}
	
	private String getSDPath(){
		File sdDir = null;
		boolean adCardExit = Environment.getExternalStorageState()
				.endsWith(Environment.MEDIA_MOUNTED);//判断SD卡是否挂载
		if (adCardExit) {
			sdDir = Environment.getExternalStorageDirectory();//获取根目录
		}
		if (sdDir != null) {
			return sdDir.toString();
		}else {
			return "";
		}
	}
	
	/**
	 * 修改文件的最后修改时间
	 * @param path
	 */
	private void updateFileTime(String path) {
		File file = new File(path);
		long newModeifyTime = System.currentTimeMillis();
		file.setLastModified(newModeifyTime);
	}

	public void saveBitmap(Bitmap bitmap,String url){
		if (bitmap == null) {
			return ;
		}
		//判断SD卡上的空间
		if(FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()){
			return;
		}
		String fileName = convertUrlToFileName(url);
		String dir = getDirectory();
		File dirFile = new File(dir);
		if (!dirFile.exists()) {
			dirFile.mkdirs();
		}
		File file = new File(dir + "/" +fileName);
		try {
			file.createNewFile();
			OutputStream outputStream = new FileOutputStream(file);
			bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
			outputStream.flush();
			outputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 计算sd卡上的剩余空间
	 * @return
	 */
	private int freeSpaceOnSd() {
		StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getPath());
		double sdFreeMB = ((double)statFs.getAvailableBlocks() * (double)statFs.getBlockSize()) / MB;
		Log.i("test", "剩余空间为:"+sdFreeMB);
		return (int)sdFreeMB;
	}
	
	/**
	 * 将url转成文件名
	 * @param url
	 * @return
	 */
	private String convertUrlToFileName(String url) {
		String[] strs = url.split("/");
		return strs[strs.length - 1] + WHOLESALE_CONV;
	}
	
	/**
	 * 计算存储目录下的文件大小
	 * 当文件总大小大于规定的大小或者sd卡剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定时
	 * ,那么删除40%最近没有被使用的文件
	 * @param dirPath
	 * @return
	 */
	private boolean removeCache(String dirPath){
		File dirFile = new File(dirPath);
		File[] files = dirFile.listFiles();
		if (files == null || files.length <= 0) {
			return true;
		}
		//如果sd卡没有挂载
		if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
			return false;
		}
		int dirSize = 0;
		for (int i = 0; i < files.length; i++) {
			if (files[i].getName().contains(WHOLESALE_CONV)) {
				dirSize += files[i].length();
			}
		}
		if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
			int removeFactor = (int)((0.4 * files.length) + 1);
			Arrays.sort(files, new FileLastModifySoft());
			for (int i = 0; i < removeFactor; i++) {
				if (files[i].getName().contains(WHOLESALE_CONV)) {
					files[i].delete();
				}
			}
		}
		if (freeSpaceOnSd() <= CACHE_SIZE) {
			return false;
		}
		return true;
 	}

	//比较器类
	private class FileLastModifySoft implements Comparator<File>{
		@Override
		public int compare(File arg0, File arg1) {
			if (arg0.lastModified() > arg1.lastModified()) {
				return 1;
			}else if (arg0.lastModified() == arg1.lastModified()) {
				return 0;
			}else {
				return -1;
			}
		}
	}
}
利用volley的networkImageview加载图片时需要传入一个ImageLoader,在构造ImageLoader时需要一个实现ImageCache接口的类,所以先构造此类:

public class ImageFileCache implements ImageCache{

	@Override
	public Bitmap getBitmap(String url) {
		return ImageFileCacheUtils.getInstance().getImage(url);
	}

	@Override
	public void putBitmap(String url, Bitmap bitmap) {
		ImageFileCacheUtils.getInstance().saveBitmap(bitmap, url);
	}

}
接下来使用networkImageview加载网络图片:

在布局文件中使用volley的自定义组件:

<com.android.volley.toolbox.NetworkImageView
                android:id="@+id/activity_icon"
                android:layout_width="@dimen/activity_icon_size_w"
                android:layout_height="@dimen/activity_icon_size_h"
                android:layout_marginRight="4dp"
                android:scaleType="centerInside"
                android:src="@drawable/activity_example" />

<pre name="code" class="java" style="color: rgb(85, 85, 85); font-size: 14px; line-height: 26px; orphans: 2; widows: 2;">//初始化imageLoader
ImageLoader imageLoader = new ImageLoader(Volley.newRequestQueue(context), new ImageFileCache());
activity_icon.setDefaultImageResId(R.drawable.activity_example);
activity_icon.setErrorImageResId(R.drawable.activity_example);
<pre name="code" class="java" style="color: rgb(85, 85, 85); font-size: 14px; line-height: 26px; orphans: 2; widows: 2;">holder.activity_icon.setImageUrl(a.getLogo(), imageLoader);
 

此模块可以直接使用在自己的项目中,希望可以帮助大家。

解析:

在实现ImageCache接口时,实现的两个方法  getBitmap   和   putBitmap  的调用时机分别是:①使用networkImageView加载图片时,首先代用getBitmap  方法,如果此方法返回的值为null,此时说明没有缓存此图片,就进行网络加载。②在进行网络加载完成后会调用   putBitmap  方法将网络获取到的图片以文件的形式缓存到SD卡,从而实现缓存的目的。

版权声明:本文为博主原创文章,需要转载,请以链接形式注明出处。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值