ListView异步加载图片

在应用开发中,经常用到ListView去加载数据,加载图片和文字是比较常见的,文字还好,图片从网络请求加载速度比较慢,所以需要把图片的加载放到另一个线程中去执行,执行完了再更新UI线程。以下列出一个我在项目中使用到的异步加载图片的解决方案,代码没有上全,给出核心部分。


大致思路是这样:

1.利用软引用来缓存图片Bitmap,用图片的URL作为缓存查找的Key;

2.设两级缓存,一级是SoftReference,二级是本地SD卡;

3.如果两级缓存都没取到图片,则从服务器获取,并加入缓存;

4.加载完后通过回调接口通知UI更新;


以下是异步加载的关键代码,其中一些工具类没有给出,自己实现就可以,比如HttpRequest是我自己写的一个类。

public class AsyncImageLoader {

	//Cache for image(Type String is the URL of image,the second parameter is soft reference)
	private HashMap<String, SoftReference<Bitmap>> imageCache = null;
	private Activity context;
	
	public AsyncImageLoader(Activity context){
		this.context = context;
		imageCache = new HashMap<String, SoftReference<Bitmap>>();
	}
	
	public Bitmap loadImage(final ImageView imageView,final String imageURL,final ImageCallBack imageCallBack){
		
		//If the cache contains the reference of bitmap then return
		if (imageCache.containsKey(imageURL)) {
			SoftReference<Bitmap> bitmapReference = imageCache.get(imageURL);
			Bitmap bitmap = bitmapReference.get();
			if (bitmap != null) {
				return bitmap;
			}
		}
		//Second cache,search local SD card
		else {
			String fileName = StringUtil.namePicture(imageURL);//获取文件名
			boolean isExist = SystemUtils.findPhotoFromSDCard(Constant.INFO_PATH, fileName);
			if (isExist) {//是否在SD卡存在图片
				Bitmap bitmap = SystemUtils.getPhotoFromSDCard(Constant.INFO_PATH, fileName);
				return bitmap;
			}
			
		}
		
		final Handler myHandler = new Handler(){
			
		@Override  
           	 public void handleMessage(Message msg)  
           	{  
               	imageCallBack.setImage(imageView, (Bitmap)msg.obj);  
           	}  
		};
		
		//If the bitmap not exists in cache or SD card,then get it from net
		new Thread(){
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				boolean isNetwork = SystemUtils.checkNetwork(context);
				if (isNetwork) {
					InputStream photoStream = HttpRequest.getImageStream(imageURL);//这里是我自己写的一个类,目的是通过URL地址从服务器获取图片输入流
					Bitmap bitmap;
					try {
						bitmap = ImageTools.getResizeBitmap(photoStream, 128, 128);
						if (bitmap != null) {
							String fileName = StringUtil.namePicture(imageURL);
							//Save image to SD card
							SystemUtils.savePhotoToSDCard(bitmap, fileName, Constant.INFO_PATH);
							//Put soft reference to cache
							imageCache.put(imageURL, new SoftReference<Bitmap>(bitmap));
							//Send message to update UI
							Message message = myHandler.obtainMessage(0, bitmap);
							myHandler.sendMessage(message);
						}
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		return null;
	}
	
	/**
	 * Interface for load image
	 * @author Ryan
	 *
	 */
	public interface ImageCallBack{
		//Set image for imageview through bitmap
		public void setImage(ImageView imageView,Bitmap bitmap);
	}
	
}

在ListView的adapter的getView方法中:

Bitmap bitmap1 = asyncImageLoader.loadImage(viewHolder.imageView1, url1, new ImageCallBack() {
				
				@Override
				public void setImage(ImageView imageView, Bitmap bitmap) {
					// TODO Auto-generated method stub
					imageView.setImageBitmap(bitmap);
				}
			});
			
			if (bitmap1 != null) {
				viewHolder.imageView1.setImageBitmap(bitmap1);
			}else {
				viewHolder.imageView1.setImageResource(R.drawable.image_bg);
			}

其中asyncImageLoader是在adapter的构造方法中初始化的,形成一个缓存。通过这个机制就可以实现ListView的图片异步加载,在用户体验上比直接加载要感觉好很多,那样会造成界面卡顿。这里是加载一张图片的情况,如果ListView的item中的图片是不定的,有可能是一张、两张、三张,该用什么方式呢,大家可以思考一下,并可以一起讨论一下,包括实现ListView滚动时不加载数据也是优化ListView加载的必要步骤。

对Android&IOS感兴趣的朋友可以加入我们的讨论QQ群,在这里,我们只讨论干货:

iOS群:220223507

Android群:282552849


欢迎关注我的新浪微博和我交流:@唐韧_Ryan



你可能感兴趣的:(String,ListView,image,null,interface,reference)