listView 图片加载性能优化

ListView是一种可以显示一系列项目并能进行滚动显示的View,每一行的Item可能包含复杂的结构,可能会从网络上获取icon等的一些图标信息,就现在的网络速度要想保持ListView运行的很好滚动流畅是做不到的

所以这里就需要把这些信息利用多线程实现异步加载

实现这样功能的类

[java]viewplaincopyprint?publicclassAsyncImageLoader{

privateHashMap<String,SoftReference<Drawable>>imageCache;

publicAsyncImageLoader(){

imageCache=newHashMap<String,SoftReference<Drawable>>();

}

publicDrawableloadDrawable(finalStringimageUrl,finalImageCallbackimageCallback){

if(imageCache.containsKey(imageUrl)){

SoftReference<Drawable>softReference=imageCache.get(imageUrl);

Drawabledrawable=softReference.get();

if(drawable!=null){

returndrawable;

}

}

finalHandlerhandler=newHandler(){

@Override

publicvoidhandleMessage(Messagemessage){

imageCallback.imageLoaded((Drawable)message.obj,imageUrl);

}

};

newThread(){

@Override

publicvoidrun(){

Drawabledrawable=loadImageFromUrl(imageUrl);

imageCache.put(imageUrl,newSoftReference<Drawable>(drawable));

Messagemessage=handler.obtainMessage(0,drawable);

handler.sendMessage(message);

}

}.start();

returnnull;

}

publicstaticDrawableloadImageFromUrl(Stringurl){

//...

}

publicinterfaceImageCallback{

publicvoidimageLoaded(DrawableimageDrawable,StringimageUrl);

}

}

publicclassAsyncImageLoader{

privateHashMap<String,SoftReference<Drawable>>imageCache;

publicAsyncImageLoader(){

imageCache=newHashMap<String,SoftReference<Drawable>>();

}

publicDrawableloadDrawable(finalStringimageUrl,finalImageCallbackimageCallback){

if(imageCache.containsKey(imageUrl)){

SoftReference<Drawable>softReference=imageCache.get(imageUrl);

Drawabledrawable=softReference.get();

if(drawable!=null){

returndrawable;

}

}

finalHandlerhandler=newHandler(){

@Override

publicvoidhandleMessage(Messagemessage){

imageCallback.imageLoaded((Drawable)message.obj,imageUrl);

}

};

newThread(){

@Override

publicvoidrun(){

Drawabledrawable=loadImageFromUrl(imageUrl);

imageCache.put(imageUrl,newSoftReference<Drawable>(drawable));

Messagemessage=handler.obtainMessage(0,drawable);

handler.sendMessage(message);

}

}.start();

returnnull;

}

publicstaticDrawableloadImageFromUrl(Stringurl){

//...

}

publicinterfaceImageCallback{

publicvoidimageLoaded(DrawableimageDrawable,StringimageUrl);

}

}

注意这里使用了SoftReference来缓存图片,允许GC在需要的时候可以对缓存中的图片进行清理。它这样工作:

·调用loadDrawable(ImageUrl,imageCallback),传入一个匿名实现的ImageCallback接口

·如果图片在缓存中不存在的话,图片将从单一的线程中下载并在下载结束时通过ImageCallback回调

·如果图片确实存在于缓存中,就会马上返回,不会回调ImageCallback

然后我们还可以根据09googleI/0开发者大会提到的方式来继续优化Adapter使用ViewHolder来减少一些比较费时的操作,譬如inflateXML和findViewById()等操作

[java]viewplaincopyprint?publicclassImageAndTextListAdapterextendsArrayAdapter<ImageAndText>{

privateListViewlistView;

privateAsyncImageLoaderasyncImageLoader;

publicImageAndTextListAdapter(Activityactivity,List<ImageAndText>imageAndTexts,ListViewlistView){

super(activity,0,imageAndTexts);

this.listView=listView;

asyncImageLoader=newAsyncImageLoader();

}

@Override

publicViewgetView(intposition,ViewconvertView,ViewGroupparent){

Activityactivity=(Activity)getContext();

//InflatetheviewsfromXML

ViewrowView=convertView;

ViewCacheviewCache;

if(rowView==null){

LayoutInflaterinflater=activity.getLayoutInflater();

rowView=inflater.inflate(R.layout.image_and_text_row,null);

viewCache=newViewCache(rowView);

rowView.setTag(viewCache);

}else{

viewCache=(ViewCache)rowView.getTag();

}

ImageAndTextimageAndText=getItem(position);

//LoadtheimageandsetitontheImageView

StringimageUrl=imageAndText.getImageUrl();

ImageViewimageView=viewCache.getImageView();

imageView.setTag(imageUrl);

DrawablecachedImage=asyncImageLoader.loadDrawable(imageUrl,newImageCallback(){

publicvoidimageLoaded(DrawableimageDrawable,StringimageUrl){

ImageViewimageViewByTag=(ImageView)listView.findViewWithTag(imageUrl);

if(imageViewByTag!=null){

imageViewByTag.setImageDrawable(imageDrawable);

}

}

});

imageView.setImageDrawable(cachedImage);

//SetthetextontheTextView

TextViewtextView=viewCache.getTextView();

textView.setText(imageAndText.getText());

returnrowView;

}

}

publicclassImageAndTextListAdapterextendsArrayAdapter<ImageAndText>{

privateListViewlistView;

privateAsyncImageLoaderasyncImageLoader;

publicImageAndTextListAdapter(Activityactivity,List<ImageAndText>imageAndTexts,ListViewlistView){

super(activity,0,imageAndTexts);

this.listView=listView;

asyncImageLoader=newAsyncImageLoader();

}

@Override

publicViewgetView(intposition,ViewconvertView,ViewGroupparent){

Activityactivity=(Activity)getContext();

//InflatetheviewsfromXML

ViewrowView=convertView;

ViewCacheviewCache;

if(rowView==null){

LayoutInflaterinflater=activity.getLayoutInflater();

rowView=inflater.inflate(R.layout.image_and_text_row,null);

viewCache=newViewCache(rowView);

rowView.setTag(viewCache);

}else{

viewCache=(ViewCache)rowView.getTag();

}

ImageAndTextimageAndText=getItem(position);

//LoadtheimageandsetitontheImageView

StringimageUrl=imageAndText.getImageUrl();

ImageViewimageView=viewCache.getImageView();

imageView.setTag(imageUrl);

DrawablecachedImage=asyncImageLoader.loadDrawable(imageUrl,newImageCallback(){

publicvoidimageLoaded(DrawableimageDrawable,StringimageUrl){

ImageViewimageViewByTag=(ImageView)listView.findViewWithTag(imageUrl);

if(imageViewByTag!=null){

imageViewByTag.setImageDrawable(imageDrawable);

}

}

});

imageView.setImageDrawable(cachedImage);

//SetthetextontheTextView

TextViewtextView=viewCache.getTextView();

textView.setText(imageAndText.getText());

returnrowView;

}

}

这里我们没有加载完iamge之后直接设定到相应的ImageView上,而是通过Tag查找,这里我们重用的View这里有个listView的引用来通过Tag查找可见CallBack的实现

[c-sharp]viewplaincopyprint?ImageViewimageViewByTag=(ImageView)listView.findViewWithTag(imageUrl);

if(imageViewByTag!=null){

imageViewByTag.setImageDrawable(imageDrawable);

}

ImageViewimageViewByTag=(ImageView)listView.findViewWithTag(imageUrl);

if(imageViewByTag!=null){

imageViewByTag.setImageDrawable(imageDrawable);

}

这里通过ViewCatch来减少了findViewById的使用

[c-sharp]viewplaincopyprint?publicclassViewCache{

privateViewbaseView;

privateTextViewtextView;

privateImageViewimageView;

publicViewCache(ViewbaseView){

this.baseView=baseView;

}

publicTextViewgetTextView(){

if(textView==null){

textView=(TextView)baseView.findViewById(R.id.text);

}

returntitleView;

}

publicImageViewgetImageView(){

if(imageView==null){

imageView=(ImageView)baseView.findViewById(R.id.image);

}

returnimageView;

}

}

publicclassViewCache{

privateViewbaseView;

privateTextViewtextView;

privateImageViewimageView;

publicViewCache(ViewbaseView){

this.baseView=baseView;

}

publicTextViewgetTextView(){

if(textView==null){

textView=(TextView)baseView.findViewById(R.id.text);

}

returntitleView;

}

publicImageViewgetImageView(){

if(imageView==null){

imageView=(ImageView)baseView.findViewById(R.id.image);

}

returnimageView;

}

}

总结:这里主要做了三点优化

在单一线程里加载图片

重用列表中行

缓存行中的View

相关推荐