使用LruCache和DiskLruCache来下载图片
Posted jzssuanfa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用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; }
效果图:
以上是关于使用LruCache和DiskLruCache来下载图片的主要内容,如果未能解决你的问题,请参考以下文章
Android 缓存LruCache和DiskLruCache
综合使用LruCache和DiskLruCache 缓存图片
Android照片墙完整版,完美结合LruCache和DiskLruCache