【 tulaoshi.com - 编程语言 】
                             
                            在应用开发中,经常用到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 HashMapString, SoftReferenceBitmap imageCache = null; 
private Activity context; 
public AsyncImageLoader(Activity context){ 
this.context = context; 
imageCache = new HashMapString, SoftReferenceBitmap(); 
} 
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)) { 
SoftReferenceBitmap 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 SoftReferenceBitmap(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加载的必要步骤。