FileCache.java如下:
package cn.loadImages;import java.io.File;import android.content.Context;import android.net.Uri;import android.os.Environment;public class FileCache { private File fileCacheDir; public FileCache(Context context){ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ fileCacheDir=new File(Environment.getExternalStorageDirectory(),"idealLV001"); } else{ //context.getCacheDir(); //擷取快取檔案所在的目錄 fileCacheDir=context.getCacheDir(); } if(!fileCacheDir.exists()){ fileCacheDir.mkdirs(); } } public File getImageFile(String url){ //String filename=String.valueOf(url.hashCode()); //String filename = URLEncoder.encode(url); Uri uri=Uri.parse(url); String fileName=uri.getLastPathSegment(); File file= new File(fileCacheDir, fileName); return file; } public void clear() {File[] files = fileCacheDir.listFiles();if (files == null) {return;}for (File file : files) {file.delete();}}}
MemoryCache.java如下:
package cn.loadImages;import java.lang.ref.SoftReference;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.Map;import java.util.Map.Entry;import java.util.concurrent.ConcurrentHashMap;import android.graphics.Bitmap;import android.util.Log;public class MemoryCache { private static final String TAG = "xx"; public static HashMap<String, Integer> bitmapsSizeHashMap; //1 建立一級緩衝 // 注意:利用了Collections.synchronizedMap使其變為一個同步的map private Map<String, Bitmap> hardBitmapCacheHashMap= Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10,1.5f,true)); //2 建立二級緩衝 private final static ConcurrentHashMap<String, SoftReference<Bitmap>> softBitmapCacheHashMap = new ConcurrentHashMap<String, SoftReference<Bitmap>>(20); //一級緩衝分配的總大小 private long allocatedMemoryMaxSize=0; //一級緩衝已使用的大小 private long nowTotalUsedMemorySize=0; public MemoryCache(){ //use 10% of available heap size setAllocatedMemoryMaxSize(Runtime.getRuntime().maxMemory()/10);//85 bitmapsSizeHashMap=new HashMap<String, Integer>(); } public void setAllocatedMemoryMaxSize(long allocatedMemoryMaxSize){ this.allocatedMemoryMaxSize=allocatedMemoryMaxSize; Log.i(TAG, "allocatedMemoryMaxSize="+allocatedMemoryMaxSize/1024/1024+"MB"); }public Bitmap getBitmapFromMemory(String url) {try {//1 從一級緩衝中尋找圖片Bitmap bitmap = hardBitmapCacheHashMap.get(url);if (bitmap != null) {// 既然現在要得到此圖片,則該圖片為最近被使用// 即在所有的對象中為最新的對象.// 所以先將該對象從hardBitmapCacheHashMap中移除// 再將其插入到hardBitmapCacheHashMap的最前面hardBitmapCacheHashMap.remove(url);hardBitmapCacheHashMap.put(url, bitmap);return bitmap;} //2 從二級緩衝中尋找圖片// 因為:若在sHardBitmapCache中沒有,那麼可能是因為該對象太陳舊// 且sHardBitmapCache容量已達上限,所以將其存入softBitmapCacheHashMap// 所以嘗試從softBitmapCacheHashMap中擷取對象 System.out.println("88 get方法中從SoftReference擷取"); System.out.println("88 get方法中從SoftReference擷取的url="+url);SoftReference<Bitmap> bitmapReference = softBitmapCacheHashMap.get(url);if (bitmapReference != null) {Bitmap bp = bitmapReference.get();if (bp != null) {return bp;} else {// SoftReference已被GC回收softBitmapCacheHashMap.remove(url);}}return null;} catch (NullPointerException ex) {ex.printStackTrace();return null;}} public void putBitmapToMemory(String url, Bitmap bitmap){ try{ if(!hardBitmapCacheHashMap.containsKey(url)){ nowTotalUsedMemorySize+=getBitmapSizeInBytes(bitmap,url); System.out.println("88 put方法中 nowTotalUsedMemorySize="+nowTotalUsedMemorySize); checkMemorySizeStatus(); hardBitmapCacheHashMap.put(url, bitmap); } }catch(Throwable th){ th.printStackTrace(); } } //檢查一級緩衝的使用方式 //若一級緩衝已達上限,則將該緩衝中組後一個元素放入二級緩衝softBitmapCacheHashMap中 //再將其充一級緩衝hardBitmapCacheHashMap中刪除 private void checkMemorySizeStatus() { int hardBitmapCacheHashMapSize=hardBitmapCacheHashMap.size(); int count=0; System.out.println("88 checkSizeStatus方法中 nowTotalUsedMemorySize="+nowTotalUsedMemorySize); System.out.println("88 checkSizeStatus方法中 memoryMaxSize="+allocatedMemoryMaxSize); if(nowTotalUsedMemorySize>=allocatedMemoryMaxSize){ System.out.println("88 checkSizeStatus方法中 滿足nowTotalUsedMemorySize>=memoryMaxSize"); System.out.println("88 checkSizeStatus方法中 hardBitmapCacheHashMap.size()="+hardBitmapCacheHashMap.size()); Iterator<Entry<String, Bitmap>> iter=hardBitmapCacheHashMap.entrySet().iterator(); //least recently accessed item will be the first one iterated while(iter.hasNext()){ count++; Entry<String, Bitmap> entry=iter.next(); if (count==hardBitmapCacheHashMapSize) { System.out.println("88 checkSizeStatus方法中 count="+count); System.out.println("88 checkSizeStatus方法中 memoryMaxSize="+allocatedMemoryMaxSize); System.out.println("88 checkSizeStatus方法中 刪除前 nowTotalUsedMemorySize="+nowTotalUsedMemorySize); nowTotalUsedMemorySize-=getBitmapSizeInBytes(entry.getValue(),entry.getKey()); //1將最後一個元素放到softBitmapCacheHashMap中 softBitmapCacheHashMap.put(entry.getKey(),new SoftReference<Bitmap>(entry.getValue())); System.out.println("88 checkSizeStatus方法中放到SoftReference的url="+entry.getKey()); System.out.println("88 checkSizeStatus方法中放入SoftReference後softBitmapCacheHashMap.size()="+softBitmapCacheHashMap.size()); //2 刪除最後的這一個元素 iter.remove(); //3 從bitmapsSizeHashMap中刪除該元素 bitmapsSizeHashMap.remove(entry.getKey()); System.out.println("88 checkSizeStatus方法中 刪除後 hardBitmapCacheHashMap.size()="+hardBitmapCacheHashMap.size()); System.out.println("88 checkSizeStatus方法中 刪除後 softBitmapCacheHashMap.size()="+softBitmapCacheHashMap.size()); System.out.println("88 checkSizeStatus方法中 刪除後 nowTotalUsedMemorySize="+nowTotalUsedMemorySize); System.out.println("88 checkSizeStatus方法中 刪除後 memoryMaxSize="+allocatedMemoryMaxSize); } } } if(nowTotalUsedMemorySize>=allocatedMemoryMaxSize){ checkMemorySizeStatus(); } } public void clear() { try{ hardBitmapCacheHashMap.clear(); softBitmapCacheHashMap.clear(); bitmapsSizeHashMap.clear(); nowTotalUsedMemorySize=0; }catch(NullPointerException ex){ ex.printStackTrace(); } } //得到Bitmap的大小 long getBitmapSizeInBytes(Bitmap bitmap,String url) { if(bitmap==null){ return 0; } int bitmapSize=bitmapsSizeHashMap.get(url); return bitmapSize; //return bitmap.getRowBytes() * bitmap.getHeight(); } }
ImageLoader.java如下:
package cn.loadImages;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;import java.util.Collections;import java.util.Map;import java.util.WeakHashMap;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.widget.ImageView;import cn.ideallistview.R;public class ImageLoader { MemoryCache memoryCache=new MemoryCache(); FileCache fileCache; private boolean isgetBitmapThumbnail=false; private final int REQUIRED_BITMAP_WIDTH=50; private final int REQUIRED_BITMAP_HEIGHT=50; private final int REQUIRED_BITMAP_MAXNUMOFPIXELS=200*200; //參見文檔: //WeakHashMap像大多數集合類一樣,是不同步的. //可使用 Collections.synchronizedMap方法來構造同步的WeakHashMap private Map<ImageView, String> imageViewsWeakHashMap= Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); ExecutorService executorService; //預設的圖片 final int defaultImageId=R.drawable.stub; public ImageLoader(Context context){ fileCache=new FileCache(context); //建立一個可重用固定線程集合的線程池,以共用的無界隊列方式來運行這些線程 executorService=Executors.newFixedThreadPool(5); } //顯示網狀圖片 public void displayImage(String url, ImageView imageView){ //1 將imageView和其對應的url放入imageViewsWeakHashMap中 imageViewsWeakHashMap.put(imageView, url); //2 試圖從記憶體中得到圖片 Bitmap bitmap=memoryCache.getBitmapFromMemory(url); if(bitmap!=null){ imageView.setImageBitmap(bitmap); } //3 不在記憶體中,則從SD卡和網路上擷取 else{ taskQueueForImages(url, imageView); imageView.setImageResource(defaultImageId); } } private void taskQueueForImages(String url, ImageView imageView){ WillLoadedImageBean willLoadedImageBean=new WillLoadedImageBean(url, imageView); //提交一個 Runnable任務用於執行,並返回一個表示該任務的 Future executorService.submit(new LoaderImagesRunnable(willLoadedImageBean)); } //該線程線上程池中運行 class LoaderImagesRunnable implements Runnable { WillLoadedImageBean willLoadedImageBean; LoaderImagesRunnable(WillLoadedImageBean willLoadedImageBean){ this.willLoadedImageBean=willLoadedImageBean; } @Override public void run() { try{ if(isImageViewReused(willLoadedImageBean)){ return; } //依據圖片Url獲得其對應的Bitmap //1 從SDCard中尋找 //2 若不在SDCard中,則從網路下載,且將圖片存至SDCard中 //3 將SDCard中圖片返回至此 Bitmap bitmap=getBitmapByUrl(willLoadedImageBean.url); //4 將圖片存至memoryCache中 memoryCache.putBitmapToMemory(willLoadedImageBean.url, bitmap); if(isImageViewReused(willLoadedImageBean)){ return; } //5 將Bitmap在UI中顯示 BitmapDisplayerRunnableInUIThread bitmapDisplayerRunnable =new BitmapDisplayerRunnableInUIThread(bitmap, willLoadedImageBean); Activity activity=(Activity)willLoadedImageBean.imageView.getContext(); activity.runOnUiThread(bitmapDisplayerRunnable); }catch(Throwable th){ th.printStackTrace(); } } } //通過Url得到其對應的Bitmap private Bitmap getBitmapByUrl(String url) { //1 從SD卡中擷取 File file=fileCache.getImageFile(url); Bitmap bitmap = getBitmapFromSDCardFile(file); if(bitmap!=null){ return bitmap; }else{ //2 若不存在SD卡中,則從網路下載並存至SD卡的File檔案中 bitmap=getBitmapFromNetWork(url,file); if (bitmap!=null) {return bitmap;} }return null; } private Bitmap getBitmapFromSDCardFile(File file) {if (!isgetBitmapThumbnail) {try {FileInputStream inputStream = new FileInputStream(file);Bitmap bitmap = BitmapFactory.decodeStream(inputStream);inputStream.close();return bitmap;} catch (Exception e) {e.printStackTrace();}} else {try {String filePath=file.getAbsolutePath();int minSideLength=Math.min(REQUIRED_BITMAP_HEIGHT, REQUIRED_BITMAP_WIDTH);Bitmap bp=Utils.getBitmapThumbnail(filePath, minSideLength, REQUIRED_BITMAP_MAXNUMOFPIXELS); return bp;} catch (Exception e) {e.printStackTrace();}}return null;}// private Bitmap getBitmapFromSDCardFile(File file){// try {// //decode image size// BitmapFactory.Options options1 = new BitmapFactory.Options();// options1.inJustDecodeBounds = true;// FileInputStream stream1=new FileInputStream(file);// BitmapFactory.decodeStream(stream1,null,options1);// stream1.close();// // //Find the correct scale value. It should be the power of 2.// final int REQUIRED_SIZE=70;// int width_tmp=options1.outWidth, height_tmp=options1.outHeight;// int scale=1;// while(true){// if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)// break;// width_tmp/=2;// height_tmp/=2;// scale*=2;// }// // //decode with inSampleSize// BitmapFactory.Options options2 = new BitmapFactory.Options();// options2.inSampleSize=scale;// FileInputStream stream2=new FileInputStream(file);// Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, options2);// stream2.close();// // System.out.println("xxxxxxxxxxxxxxxxx f.getPath="+file.getPath());// System.out.println("xxxxxxxxxxxxxxxxx options1.outWidth="+options1.outWidth);// System.out.println("xxxxxxxxxxxxxxxxx options1.outHeight="+options1.outHeight);// System.out.println("xxxxxxxxxxxxxxxxx scale="+scale);// return bitmap;// } catch (FileNotFoundException e) {// } // catch (IOException e) {// e.printStackTrace();// }// return null;// } //網路下載圖片且儲存到SDCard private Bitmap getBitmapFromNetWork(String url,File file){ try { Bitmap bitmap=null; URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is=conn.getInputStream(); //儲存其大小 MemoryCache.bitmapsSizeHashMap.put(url,conn.getContentLength()); OutputStream os = new FileOutputStream(file); Utils.copyStream(is, os); os.close(); bitmap = getBitmapFromSDCardFile(file); return bitmap; } catch (Throwable ex){ ex.printStackTrace(); if(ex instanceof OutOfMemoryError){ memoryCache.clear(); } return null; } } //在UI線程中顯示Bitmap class BitmapDisplayerRunnableInUIThread implements Runnable{ Bitmap bitmap; WillLoadedImageBean willLoadedImageBean; public BitmapDisplayerRunnableInUIThread(Bitmap bitmap, WillLoadedImageBean willLoadedImageBean){ this.bitmap=bitmap; this.willLoadedImageBean=willLoadedImageBean; } public void run(){ if(isImageViewReused(willLoadedImageBean)){ return; } if(bitmap!=null){ willLoadedImageBean.imageView.setImageBitmap(bitmap); } else{ willLoadedImageBean.imageView.setImageResource(defaultImageId); } } } //Task for the queue private class WillLoadedImageBean { public String url; public ImageView imageView; public WillLoadedImageBean(String url, ImageView imageView){ this.url=url; this.imageView=imageView; } } boolean isImageViewReused(WillLoadedImageBean willLoadedImageBean){ String imageUrl=imageViewsWeakHashMap.get(willLoadedImageBean.imageView); if(imageUrl==null || !imageUrl.equals(willLoadedImageBean.url)){ return true; } return false; } public void clearCache() { memoryCache.clear(); fileCache.clear(); }}