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(); } }