ListView异步加载图片实现思路
程序员文章站
2023-12-12 19:11:04
在应用开发中,经常用到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加载的必要步骤。
大致思路是这样:
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加载的必要步骤。