图片异步加载2

之前的 图片异步加载1用采用的是内存记忆存储的方式异步加载图片、而现在我将采用、内存记忆存储和本地缓存方式、并且采用惰性的方式来实现ListView的图片异步加载、

这种方式相对于第一种方式来说、更节省流量、并且更人性化、

异步加载的实现核心代码如下、

public class BitmapLoader {
	
	private Map<ImageView,String> imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView,String>());
	
	//记忆缓存
	private HashMap<String, SoftReference<Bitmap>> memoryCache;
	
	//文件缓存
	private FileCache fileCache;
	
	
	//默认图片id
	private int defaultDrawableId;

	//-------------------------
	
	private ImageStack imageStack;
	
	private ImageLoaderThread imageLoaderThread;
	
	public BitmapLoader(int defaultDrawableId){
		
		this.defaultDrawableId = defaultDrawableId;
		init(null);

	}
	
	public BitmapLoader(int defaultDrawableId,String pojectName){
		
		this.defaultDrawableId = defaultDrawableId;
		init(SDCARD_PATH+pojectName+"/cache");
		
	}
	
	private void init(String dirName){
		memoryCache = new HashMap<String, SoftReference<Bitmap>>();
		
		fileCache = new FileCache(dirName);
		
		imageStack = new ImageStack();
		
		imageLoaderThread = new ImageLoaderThread();
		imageLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
	}
	
	//----------------------------------------------
	/**
	 * 显示图片
	 * @param url
	 * @param imageView
	 */
	public void displayImage(String url,ImageView imageView){
		imageViews.put(imageView,url);
		
		Bitmap bitmap = null;
		if(memoryCache.containsKey(url)){
			bitmap = memoryCache.get(url).get();
		}
		
		if(bitmap!=null){
			imageView.setImageBitmap(bitmap);
		}else{
			//清扫之前存在的
			imageStack.clean(imageView);
			ImageInfo imageInfo = new ImageInfo(url, imageView);
			synchronized (imageStack.imageStacks) {
				//压入栈
				imageStack.imageStacks.push(imageInfo);
				imageStack.imageStacks.notifyAll();
			}
			//...
			imageView.setImageResource(defaultDrawableId);
			
			if(imageLoaderThread.getState() == Thread.State.NEW){
				imageLoaderThread.start();
			}
		}
		
	}
	
	/**
	 * 停止线程
	 */
	public void stopThread(){
		imageLoaderThread.interrupt();
	}
	
	/**
	 * 清楚缓存
	 */
	public void clearCache(){
		memoryCache.clear();
		fileCache.clear();
	}
	
	
	//----------------------------------------------
	/**
	 * 图片加载线程
	 */
	class ImageLoaderThread extends Thread{
		
		
		@Override
		public void run() {
			try{
				while(true){
					if(imageStack.imageStacks.size()==0){
						synchronized (imageStack.imageStacks) {
							imageStack.imageStacks.wait();
						}
					}
					if(imageStack.imageStacks.size()!=0){
						ImageInfo imageInfo;
						synchronized (imageStack.imageStacks) {
							 imageInfo = imageStack.imageStacks.pop();
						}
						final Bitmap bitmap = downloadBitmap(imageInfo.url);
						memoryCache.put(imageInfo.url,new SoftReference<Bitmap>(bitmap));
						String url = imageViews.get(imageInfo.imageView);
						if(url!=null && url.equals(imageInfo.url)){
							
							Activity activity = (Activity)imageInfo.imageView.getContext();
							activity.runOnUiThread(new ImageViewRunnable(imageInfo.imageView,bitmap,defaultDrawableId));
						}
					}
					
					if(Thread.interrupted()){
						break;
					}
				}
			}catch(InterruptedException e){
				LogUtils.logE("异常:" + e.getMessage());
			}
		}
		
		/**
		 * 下载图片
		 * @param url
		 * @return
		 */
		public Bitmap downloadBitmap(String url){
			//...
			
			File file = fileCache.getFile(url);
			
			Bitmap bitmap = decodeFile(file);
			
			if(bitmap!=null){
				return bitmap;
			}
			
			try{
				
				URL imageUrl = new URL(url);
				HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
				conn.setConnectTimeout(10000);
				conn.setReadTimeout(10000);
				
				InputStream is=conn.getInputStream();
				FileUtils.writeFileByImputStream(file.getAbsolutePath(),is);
				return decodeFile(file);
				
			}catch(Exception e){
				LogUtils.logE("异常:"+ e.getMessage());
				return null;
			}
			
			
		}
		
		
		private Bitmap decodeFile(File file){
			try{
				LogUtils.logI(file.getPath());
				
				BitmapFactory.Options opt = new BitmapFactory.Options();
				
				opt.inJustDecodeBounds = true;
				
				 BitmapFactory.decodeStream(new FileInputStream(file),null,opt);
				
	            final int REQUIRED_SIZE=100;
	            int width_tmp=opt.outWidth, height_tmp=opt.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;
	            }
	            
	            BitmapFactory.Options opt2 = new BitmapFactory.Options();
	            opt2.inSampleSize=scale;
	            return BitmapFactory.decodeStream(new FileInputStream(file), null, opt2);
				
			}catch(FileNotFoundException e){
//				LogUtils.logE("文件不存在!");
				return null;
			}
		}
		
		/**
		 * 图片显示
		 */
		class ImageViewRunnable implements Runnable{
			
			ImageView imageView;
			Bitmap bitmap;
			int defaultDrawable;
			
			public ImageViewRunnable(ImageView iv,Bitmap bmp,int defaultDrawableId){
				 this.imageView = iv;
				 this.bitmap = bmp;
				 this.defaultDrawable = defaultDrawableId;
			}
			
			public void run(){
				if(bitmap!=null){
					imageView.setImageBitmap(bitmap);
				}else{
					imageView.setImageResource(defaultDrawable);
				}
			}
			
		}
		
	}
	
	
	//----------------------------------------------
	/**
	 * 图片栈
	 */
	class ImageStack{
		
		private Stack<ImageInfo> imageStacks = new Stack<ImageInfo>();
		
		private void clean(ImageView imageView){
			
			for(int i=0;i<imageStacks.size();){
				if(imageStacks.get(i).imageView==imageView){
					imageStacks.remove(i);
				}else{
					++i;
				}
			}
		}
		
		
	}
	
	/**
	 * 图片信息
	 */
	class ImageInfo{
		String url;
		ImageView imageView;
		
		public ImageInfo(String url,ImageView imageView){
			this.url = url;
			this.imageView = imageView;
		}
	}
	
	//----------------------------------------------
	/**
	 * 本地文件缓存
	 */
	class FileCache{
		
		File dirCache = null;
		
		public FileCache(){
			if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){
				dirCache = FileUtils.createNewDir(SDCARD_PATH+"cache");
				
			}
		}
		
		/**
		 * 构造
		 * @param path 本地缓存
		 */
		public FileCache(String dirName){
			if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){ 
				
				if(dirName!=null){
					dirCache = FileUtils.createNewDir(dirName);
				}else{
					dirCache = FileUtils.createNewDir(SDCARD_PATH+"cache");
				}
				
			}
		}
		
		/**
		 * 获取缓存文件
		 * @param url
		 * @return
		 */
		public File getFile(String url){
			
			if(dirCache!=null){
				String fileName = String.valueOf(url.hashCode());
				return new File(dirCache,fileName);
			}
			
			return null;
		}
		
		/**
		 * 清空缓存文件
		 */
		public void clear(){
		  if(dirCache!=null){
			  File[] files = dirCache.listFiles();
			  
			  for(File file:files){
				  file.delete();
			  }
		  }
		}
		
		
	}
	
	//----------------------------------------------
	
	public static final String SDCARD_PATH = FileUtils.SDCARD_PATH;
	
}


用到的工具类FileUtisl的方法、

	public static File createNewDir(String path){
		File file = new File(path);
		try {
			if(!file.exists()){
				file.mkdirs();
			}
		} catch (Exception e) {
			LogUtils.logE(CLAZZ,"创建新文件夹出错:"+e.getMessage());
		}
		return file;
	}


	public static File writeFileByImputStream(String path,InputStream input)throws IOException{
		
		File file = null;
		
		OutputStream output = null;
		try{
			file = new File(path);
			output = new FileOutputStream(file); 
			
			byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
			
			while((input.read(buffer))!=-1){
				output.write(buffer);
			}
			output.flush();
			
		}catch(IOException e){
			throw e;
		}finally{
			try{
				if(output!=null){
					output.close();
				}
			}catch (IOException e) {
				output = null;
			}
		}
		return file;
	}


直接在自定义的Adapte里面实例化个bitmapLoader然后在自定义的Adapter的getView方法里面调用 bitmapLoader.displayImage(url, imageView);就ok了、


测试效果图:



posted @ 2013-08-23 11:38  Jenly  阅读(125)  评论(0编辑  收藏  举报