Android异步加载图片详解之方式一(2)
来源:互联网 发布:svs软件 编辑:程序博客网 时间:2024/05/22 17:23
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(); }}
- Android异步加载图片详解之方式一(2)
- Android异步加载图片详解之方式一(4)
- Android异步加载图片详解之方式一(3)
- Android异步加载图片详解之方式一(1)
- Android异步加载图片详解之方式二(2)
- Android异步加载图片详解之方式二(3)
- Android异步加载图片详解之方式二(1)
- android之图片异步加载
- Android图片异步加载之Universal-Image-Loader(一)
- android多种方式实现异步加载图片
- android开发-异步图片加载(一)
- Android之handle异步加载图片
- android 之图片异步加载,带缓存。
- Android开发之ListView异步加载图片
- Android之异步加载网络图片
- Android异步图片加载组件之 Universal_image_loader
- Android有效加载图片 之 使用AsyncTask异步加载图片
- android异步加载之Handler、AsyncTask(一)
- Android异步加载图片详解之方式一(3)
- 欧拉计划:相似的18题和67题,以及简单的20题100!,以及19题
- NSDATA如何转成NSString
- sprintf(c++)
- 如何培养软件工程人才——参加“第一届高等学校软件工程人才培养高峰论坛”有感
- Android异步加载图片详解之方式一(2)
- 触发器中New与Old的区别
- C#数字千分位问题
- 使用Xcode和Instruments调试解决iOS内存泄露
- linux NAND驱动之一:内核中的NAND代码布局
- 使用libvirt创建kvm虚拟机
- 程序员面试100题之十八 十四 两个栈实现队列
- Android异步加载图片详解之方式一(1)
- Twitter的照片滤镜功能可能已经上线,内部员工正在对IOS和Android平台应用程序上进行测试