使用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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章