使用LruCache和DiskLruCache来下载图片

LruCache是一个非常好用的图片缓存工具:

主要做法是:滑动图片时将图片的bitmap缓存在LruCache<String, Bitmap>中,退出程序后将图片缓存进文件中。採用DiskLruCache mDiskLruCache

所以我们必须设置一个图片缓存的地址:

public void setImageCache(){
    	String strPath = null;
    	if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
	    	File sdFile = Environment.getExternalStorageDirectory();
	    	strPath = sdFile.getAbsolutePath() + "/pic/";
	    	File cacheFile = new File(strPath);
	        if(!cacheFile.exists()){
	        	cacheFile.mkdir();
	        }
	    }
    	else{
    		String strCacheDir = this.getCacheDir().getAbsolutePath();
    		strPath = strCacheDir + "/pic/";
    	}
    	setCachePath(strPath);
    }

	private void setCachePath(String strPicCachePath){
		if(TextUtils.isEmpty(strPicCachePath)){
			return;
		}
		m_strPicCachePath = strPicCachePath;
		File cacheFile = new File(strPicCachePath);
        if(!cacheFile.exists()){
        	cacheFile.mkdir();
        }
	}

	public String getCacheBmpPath(String strUrl){
		if(TextUtils.isEmpty(m_strPicCachePath) || TextUtils.isEmpty(strUrl)){
			return "";
		}
		return m_strPicCachePath + StringUtil.MD5Encode(strUrl) + mFileExName;//".bmp";
	}

然后写List的adapter:

	private class ListAdapter extends BaseAdapter implements OnScrollListener {

		protected List<ShopData> items = new ArrayList<ShopData>();
		protected static final int FETCH_IMAGE_MSG = 1;
		private LruCache<String, Bitmap> mMemoryCache;
		protected HashSet<ImageView> mItemsMissingImages = new HashSet<ImageView>();
		protected ImageLoaderHandler mHandler;
		protected ImageLoader mImageFetcher;
		public static final int TIMEOUT = 30000;//超时时间30秒
		private DiskLruCache mDiskLruCache;  

		public ListAdapter() {
			super();
			mHandler = new ImageLoaderHandler();
			int maxMemory = (int) Runtime.getRuntime().maxMemory();
			int mCacheSize = maxMemory / 8;
			// 给LruCache分配1/8 4M
			mMemoryCache = new LruCache<String, Bitmap>(mCacheSize) {

				// 必须重写此方法,来測量Bitmap的大小
				@Override
				protected int sizeOf(String key, Bitmap value) {
					return value.getRowBytes() * value.getHeight();
				}

			};

		 try {
			mDiskLruCache = DiskLruCache
			                .open(new File(m_strPicCachePath), getAppVersion(MainActivityTest.this), 1, 10 * 1024 * 1024);
		} catch (IOException e) {
			e.printStackTrace();
		}  

		}

		/**
		 * 将缓存记录同步到journal文件里。

*/
		public void fluchCache() {
			if (mDiskLruCache != null) {
				try {
					mDiskLruCache.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		@Override
		public int getCount() {
			return items.size();
		}

		@Override
		public Object getItem(int position) {
			return items.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			ShopDataTag tag = new ShopDataTag();
			if (convertView == null) {
				convertView = mInflater.inflate(R.layout.listitem, null);
				tag.name = (TextView) convertView.findViewById(R.id.name);
				tag.shopInfo = (TextView) convertView.findViewById(R.id.info);
				tag.icon = (ImageView) convertView.findViewById(R.id.image_icon);
				convertView.setTag(tag);
			} else {
				tag = (ShopDataTag) convertView.getTag();
			}

			TextView name = tag.name;
			TextView info = tag.shopInfo;
			ImageView imageView = tag.icon;
			ShopData data = items.get(position);
			name.setText(data.name);
			info.setText(data.info);
			imageView.setTag(data.url);
			setContactPhoto(data.url, imageView);
			return convertView;
		}

		protected void setContactPhoto(String url,ImageView viewToUse) {
			if(TextUtils.isEmpty(url)) {
				viewToUse.setImageResource(R.drawable.avatar);
			}else{
				//先看mMemoryCache里能不能得到bitmap
				Bitmap bitmap = mMemoryCache.get(url);
				if (bitmap != null) {
					viewToUse.setImageBitmap(bitmap);
				} else {
					Snapshot snapShot = null;
					FileDescriptor fileDescriptor = null;
					FileInputStream fileInputStream = null;
					try {
						//由于mDiskLruCache会把key作为文件名称。所以把url通过md5转换为key
						final String key = hashKeyForDisk(url);
						snapShot = mDiskLruCache.get(key);
						//假设snapShot为空,就是没找到相应的文件
						if (snapShot == null) {
							//这里去下载
							fetchImage(viewToUse);
						}else{
							fileInputStream = (FileInputStream) snapShot.getInputStream(0);
							fileDescriptor = fileInputStream.getFD();
							if (fileDescriptor != null) {
								bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
							}
							//假设解析文件成bitmap失败。又一次下载
							if(!TextUtils.isEmpty(url) && bitmap != null){
								mMemoryCache.put(url, bitmap);
								viewToUse.setImageBitmap(bitmap);
							}else{
								fetchImage(viewToUse);
							}
						}
					}catch(IOException ex) {
						ex.printStackTrace();
					}finally{
						if (fileDescriptor == null && fileInputStream != null) {
							try {
								fileInputStream.close();
							} catch (IOException e) {
							}
						}
					}

				}
			}
		}

		private void fetchImage(ImageView viewToUse) {
			viewToUse.setImageResource(R.drawable.avatar);
			mItemsMissingImages.add(viewToUse);
			if (mScrollState != OnScrollListener.SCROLL_STATE_FLING) {
				sendFetchImageMessage(viewToUse);
			}
		}

		public String <strong>hashKeyForDisk</strong>(String key) {     将key转换为md5文件
			return StringUtil.MD5Encode(key);
		}

		// image downloader
		private class ImageLoaderHandler extends Handler {
			@Override
			public void handleMessage(Message message) {
				if (isFinishing()) {
					return;
				}
				switch (message.what) {
				case FETCH_IMAGE_MSG: {
					final ImageView imageView = (ImageView) message.obj;
					if (imageView == null) {
						break;
					}

					final String url = (String) imageView.getTag();
					if (TextUtils.isEmpty(url)) {
						break;
					}

					Bitmap map = getBitmapFromMemCache(url);
					if (map == null) {
						break;
					}

					synchronized (imageView) {
						final String myUrl = (String) imageView.getTag();
						if (TextUtils.equals(url, myUrl)) {
							imageView.setImageBitmap(map);
							mItemsMissingImages.remove(imageView);
						} else {
						}
					}
					break;
				}
				}
			}

			public void clearImageFecthing() {
				removeMessages(FETCH_IMAGE_MSG);
			}
		}

		private class ImageLoader implements Runnable {
			String url;
			private ImageView mImageView;

			public ImageLoader(String url, ImageView imageView) {
				this.url = url;
				this.mImageView = imageView;
			}

			public void run() {
				if (isFinishing()) {
					return;
				}

				if (Thread.interrupted()) {
					return;
				}

				FileDescriptor fileDescriptor = null;
				FileInputStream fileInputStream = null;
				Snapshot snapShot = null;
				try {
					final String key = hashKeyForDisk(url);
					snapShot = mDiskLruCache.get(key);
					if (snapShot == null) {
						// 假设没有找到相应的缓存,则准备从网络上请求数据。并写入缓存
						DiskLruCache.Editor editor = mDiskLruCache.edit(key);
						if (editor != null) {
							OutputStream outputStream = editor.newOutputStream(0);
							boolean flag = downloadImage(url, outputStream);
							if (flag) {
								editor.commit();
							} else {
								editor.abort();
							}
						}
						// 缓存被写入后,再次查找key相应的缓存
						snapShot = mDiskLruCache.get(key);
					}
					//这里应该删除相应的文件

					if (snapShot != null) {
						fileInputStream = (FileInputStream) snapShot.getInputStream(0);
						fileDescriptor = fileInputStream.getFD();
					}

					// 将缓存数据解析成Bitmap对象
					Bitmap bitmap = null;
					if (fileDescriptor != null) {
						bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
					}
					if (bitmap != null) {
						// 将Bitmap对象加入到内存缓存其中
						mMemoryCache.put(url, bitmap);
					}
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					if (fileDescriptor == null && fileInputStream != null) {
						try {
							fileInputStream.close();
						} catch (IOException e) {
						}
					}
				}

				if (Thread.interrupted()) {
					return;
				}

				Message msg = new Message();
				msg.what = FETCH_IMAGE_MSG;
				msg.obj = mImageView;
				mHandler.sendMessage(msg);
			}
		}

		public Bitmap getBitmapFromMemCache(String key) {
		    return mMemoryCache.get(key);
		} 

		public boolean downloadImage(String strUrl,OutputStream fos) {

			URL getUrl = null;
			Bitmap bitmap = null;
			BufferedOutputStream out = null;
			BufferedInputStream in = null;
			try {
				getUrl = new URL(strUrl);
			} catch (MalformedURLException ex) {
				Log.e("HttpUtil", "get MalformedURL", ex);
				return false;
			}
			InputStream input = null;
			HttpURLConnection conn = null;
			try {
				conn =  (HttpURLConnection)getUrl.openConnection();
				conn.setConnectTimeout(TIMEOUT);
				conn.setReadTimeout(TIMEOUT);
				conn.setDoInput(true);
				conn.connect();
				input = conn.getInputStream();
				in = new BufferedInputStream(input, 8 * 1024);
				out = new BufferedOutputStream(fos, 8 * 1024);
				int b;
				while ((b = in.read()) != -1) {
					out.write(b);
				}
				return true;
			} catch (Exception ex) {
				Log.e("HttpUtil", "downloadImage", ex);
			} catch(OutOfMemoryError ex){
				ex.printStackTrace();
			} finally {
				try {
					if(out != null){
						out.close();
						out = null;
					}
					if (in != null){
						in.close();
						in = null;
					}
					if (conn != null){
						conn.disconnect();
						conn = null;
					}
				} catch (Exception ex) {
					Log.e("HttpUtil", "downloadImage finally", ex);
				}
			}
			return false;
		}

		private boolean getResponse(InputStream input, OutputStream os, byte[] data) throws IOException{
			if(input == null || os == null || data == null){
				return false;
			}
			int i = 0;
			while( (i = input.read(data)) != -1){
				os.write(data, 0, i);
				os.flush();
			}
			os.flush();
			return true;
		}

		private void processMissingImageItems(AbsListView view) {
			for (ImageView iv : mItemsMissingImages) {
				sendFetchImageMessage(iv);
			}
		}

		protected void sendFetchImageMessage(ImageView view) {
			final String url = (String) view.getTag();
			if (TextUtils.isEmpty(url)) {
				return;
			}
			mImageFetcher = new ImageLoader(url, view);
			synchronized (MainActivityTest.this) {
				if (sImageFetchThreadPool == null) {
					sImageFetchThreadPool = Executors.newFixedThreadPool(3);
				}
				sImageFetchThreadPool.execute(mImageFetcher);
			}
		}

		public void clearImageFetching() {
			synchronized (MainActivityTest.this) {
				if (sImageFetchThreadPool != null) {
					sImageFetchThreadPool.shutdownNow();
					sImageFetchThreadPool = null;
				}
			}

			mHandler.clearImageFecthing();
		}

		public void clearMessages() {
			if (mHandler != null) {
				try {
					mHandler.removeCallbacksAndMessages(null);
				} catch (java.lang.Throwable th) {
				}
				mHandler = null;
			}
		}

		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState) {
			mScrollState = scrollState;
			if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
				clearImageFetching();
			} else {
				processMissingImageItems(view);
			}
		}

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

		}

	}

	private class ShopDataTag {
		TextView name;
		TextView shopInfo;
		ImageView icon;
	}

效果图:

代码:http://download.csdn.net/detail/baidu_nod/7777137

时间: 2024-08-01 18:27:59

使用LruCache和DiskLruCache来下载图片的相关文章

Android异步批量下载图片并缓存

前言 本文引自:http://www.xycoding.com/articles/2014/07/29/android-async-images-download/,作者不详 ImagesDownLoad源码下载:DEMO 接触android开发不久,近段时间需实现一个批量下载图片并显示的小功能.在网上搜索了一圈,发现国内外网上异步加载的例子太多太杂,要么是加载大图decode时报OOM异常,要么内存急剧上升不稳定.所以在前辈们的基础上,做了一些优化,特共享出来,欢迎大家指正.这里主要参见了以下

综合使用LruCache和DiskLruCache 缓存图片

Activity public class MainActivity extends Activity {     private GridView mPhotoWall;     private PhotoWallAdapter mAdapter;     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         s

利用LruCache和DiskLruCache加载网络图片实现图片瀑布流效果(升级版)

MainActivity如下: package cc.patience7; import android.os.Bundle; import android.app.Activity; /** * Demo描述: * 采用瀑布流的形式加载大量网络图片 * 详细分析参见WaterfallScrollView * * 更新说明: * 在原本的的基础上添加了本地缓存DiskLruCache * * 所以在该示例中对于图片的缓存采用了:LruCache + DiskLruCache 的技术 * * 参考

网络图片的获取以及二级缓存策略(Volley框架+内存LruCache+磁盘DiskLruCache)

在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理,每次打开应用都去网络获取图片,那么用户可就不乐意了,这里的处理就是指今天要讲的缓存策略(缓存层分为三层:内存层,磁盘层,网络层). 关于缓存层的工作,当我们第一次打开应用获取图片时,先到网络去下载图片,然后依次存入内存缓存,磁盘缓存,当我们再一次需要用到刚才下载的这张图片时,就不需要再重复的到网络

Android照片墙完整版,完美结合LruCache和DiskLruCache

转载地址:http://blog.csdn.net/guolin_blog/article/details/34093441#comments 在上一篇文章当中,我们学习了DiskLruCache的概念和基本用法,但仅仅是掌握理论知识显然是不够的,那么本篇文章我们就来继续进阶一下,看一看在实战当中应该怎样合理使用DiskLruCache.还不熟悉DiskLruCache用法的朋友可以先去参考我的上一篇文章 Android DiskLruCache完全解析,硬盘缓存的最佳方案 . 其实,在真正的项

LrcCache和DiskLruCache相结合打造图片加载框架

LrcCache和DiskLruCache相结合打造图片加载框架 1概述 这几在研究图片加载的方面的知识,在网上看了一下前辈们写的文章,受到了一些启发,于是综合多方面的知识,将这些整合起来,自己边写了一个图片加载框架.说到图片加载最容易出问题的就是OOM就是内存溢出,所以一定要限制加载图片时使用的内存,这就使用到Android提供的缓存类LruCache,关于LruCache的知识这里不再赘述,大家自行学习.但是如果图片非常的多而且频繁操作的话,加上LruCache的缓存空间有限,缓存就不得不经

由LruCache和DiskLruCache提供三级缓存支持的ImageLoader

从三天前一直报错到今天中午,总算出了个能用的版本了. 一如既往先发链接: https://github.com/mlxy/ImageLoader 缓存处理 ·LruCacheHelper: 封装第一级缓存,也就是内存缓存的处理. LruCache是Android自带的缓存处理类,如名字所说,和使用软引用的映射相比,优势在于可以忽略缓存上限处理的细节问题,初始化时在构造函数中给一个缓存上限即可.一般做法是使用最大内存的八分之一: Runtime.getRuntime().maxMemory() /

Android照片墙完整版,的完美结合LruCache和DiskLruCache

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/34093441 在上一篇文章其中,我们学习了DiskLruCache的概念和基本使用方法.但仅仅是掌握理论知识显然是不够的,那么本篇文章我们就来继续进阶一下.看一看在实战其中应该如何合理使用DiskLruCache. 还不熟悉DiskLruCache使用方法的朋友能够先去參考我的上一篇文章 Android DiskLruCache全然解析,硬盘缓存的最佳方案 . 事实上,在真正的项

使用LruCache和DiskLruCache手写一个ImageLoader

一.概述 在分析OkHttp3的缓存机制之前先手写一个实现了三级缓存的ImageLoader来整体感受一下LruCache和DiskLruCache的用法.本例实现了三级缓存,利用LruCache实现内存缓存,利用DiskLruCache实现磁盘缓存.整体的流程是:当用户请求一张图时,首先检查内存中是否有缓存图片,如果有就直接返回,如果没有就检查磁盘中是否有,有就返回,没有就启用网络下载图片,然后把图片缓存在磁盘缓存和内存缓存中.下面看看具体的实现步骤. 二.源程序介绍 1.ImageLoade