Android ListView 异步加载图片

mark0614 12年前

ListView异步加载图片是非常实用的方法,凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,下面就说实现方法,先贴上主方法的代码:

package cn.wangmeng.test;    import java.io.IOException;  import java.io.InputStream;  import java.lang.ref.SoftReference;  import java.net.MalformedURLException;  import java.net.URL;  import java.util.HashMap;    import android.graphics.drawable.Drawable;  import android.os.Handler;  import android.os.Message;    public class AsyncImageLoader {      private HashMap<String, SoftReference<Drawable>> imageCache;             public AsyncImageLoader() {         imageCache = new HashMap<String, SoftReference<Drawable>>();        }             public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {            if (imageCache.containsKey(imageUrl)) {                SoftReference<Drawable> softReference = imageCache.get(imageUrl);                Drawable drawable = softReference.get();                if (drawable != null) {                    return drawable;                }            }            final Handler handler = new Handler() {                public void handleMessage(Message message) {                    imageCallback.imageLoaded((Drawable) message.obj, imageUrl);                }            };            new Thread() {                @Override                public void run() {                    Drawable drawable = loadImageFromUrl(imageUrl);                    imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));                    Message message = handler.obtainMessage(0, drawable);                    handler.sendMessage(message);                }            }.start();            return null;        }         public static Drawable loadImageFromUrl(String url) {     URL m;     InputStream i = null;     try {      m = new URL(url);      i = (InputStream) m.getContent();     } catch (MalformedURLException e1) {      e1.printStackTrace();     } catch (IOException e) {      e.printStackTrace();     }     Drawable d = Drawable.createFromStream(i, "src");     return d;    }             public interface ImageCallback {            public void imageLoaded(Drawable imageDrawable, String imageUrl);        }    }
以上代码是实现异步获取图片的主方法,SoftReference是软引用,是为了更好的为了系统回收变量,重复的URL直接返回已有的资源,实现回调函数,让数据成功后,更新到UI线程。
几个辅助类文件:
package cn.wangmeng.test;    public class ImageAndText {       private String imageUrl;       private String text;         public ImageAndText(String imageUrl, String text) {           this.imageUrl = imageUrl;           this.text = text;       }       public String getImageUrl() {           return imageUrl;       }       public String getText() {           return text;       }  }
package cn.wangmeng.test;    import android.view.View;  import android.widget.ImageView;  import android.widget.TextView;    public class ViewCache {         private View baseView;       private TextView textView;       private ImageView imageView;         public ViewCache(View baseView) {           this.baseView = baseView;       }         public TextView getTextView() {           if (textView == null) {               textView = (TextView) baseView.findViewById(R.id.text);           }           return textView;       }         public ImageView getImageView() {           if (imageView == null) {               imageView = (ImageView) baseView.findViewById(R.id.image);           }           return imageView;       }    }
ViewCache是辅助获取adapter的子元素布局
package cn.wangmeng.test;    import java.util.List;    import cn.wangmeng.test.AsyncImageLoader.ImageCallback;    import android.app.Activity;  import android.graphics.drawable.Drawable;  import android.view.LayoutInflater;  import android.view.View;  import android.view.ViewGroup;  import android.widget.ArrayAdapter;  import android.widget.ImageView;  import android.widget.ListView;  import android.widget.TextView;    public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {         private ListView listView;       private AsyncImageLoader asyncImageLoader;         public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {           super(activity, 0, imageAndTexts);           this.listView = listView;           asyncImageLoader = new AsyncImageLoader();       }         public View getView(int position, View convertView, ViewGroup parent) {           Activity activity = (Activity) getContext();             // Inflate the views from XML           View rowView = convertView;           ViewCache viewCache;           if (rowView == null) {               LayoutInflater inflater = activity.getLayoutInflater();               rowView = inflater.inflate(R.layout.image_and_text_row, null);               viewCache = new ViewCache(rowView);               rowView.setTag(viewCache);           } else {               viewCache = (ViewCache) rowView.getTag();           }           ImageAndText imageAndText = getItem(position);             // Load the image and set it on the ImageView           String imageUrl = imageAndText.getImageUrl();           ImageView imageView = viewCache.getImageView();           imageView.setTag(imageUrl);           Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {               public void imageLoaded(Drawable imageDrawable, String imageUrl) {                   ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);                   if (imageViewByTag != null) {                       imageViewByTag.setImageDrawable(imageDrawable);                   }               }           });     if (cachedImage == null) {      imageView.setImageResource(R.drawable.default_image);     }else{      imageView.setImageDrawable(cachedImage);     }           // Set the text on the TextView           TextView textView = viewCache.getTextView();           textView.setText(imageAndText.getText());             return rowView;       }    }
ImageAndTextListAdapter是实现ListView的Adapter,里面有个技巧就是imageView.setTag(imageUrl),setTag是存储数据的,这样是为了保证在回调函数时,listview去更新自己对应item,大家仔细阅读就知道了。
最后贴出布局文件:
<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"                android:orientation="horizontal"                android:layout_width="fill_parent"                android:layout_height="wrap_content">            <ImageView android:id="@+id/image"                     android:layout_width="wrap_content"                     android:layout_height="wrap_content"                     />            <TextView android:id="@+id/text"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"/>    </LinearLayout>