Android实现ListView异步加载图片总结
参考自 http://blog.csdn.net/wanglong0537/article/details/6334005#
http://www.cnblogs.com/slider/archive/2011/11/22/2258942.html
http://www.iteye.com/topic/685986
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));//把获得的drawable存入缓存 Message message = handler.obtainMessage(0, drawable);//obtainmessage()与new message类似 //obtainmessage()是从消息池拿来的一个msg,不必另开空间new handler.sendMessage(message); } }.start(); return null; } //从图片url获取图片drawable对象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来缓存图片,允许 GC在需要的时候可以对缓存中的图片进行清理。
异步加载图片类AsyncImageLoader的实现方式
1,在自定义的adapter中调用 loadDrawable(ImageUrl, imageCallback),传入图片的网络地址和一个实现ImageCallback行为的对象(一个匿名实现的 ImageCallback接口的对象)
2,如果图片(通过imageUrl这个key值来判断)在缓存imageCache中不存在的话,图片将从单一(异步)的线程中下载并在下载结束时Drawable返回为null并通过 ImageCallback回调在 ImageAndTextListAdapter类中实现的imageLoaded方法
3,如果图片确实存在于缓存中,就会马上返回drawable给adapter类的cachedImage,不会回调 ImageCallback
注:HashMap<String, SoftReference<Drawable>>(); 和平常常用的HashMap<key,value>是一样的
注:关于软引用:在Java中内存管理,引用分为四大类,强引用HardReference、弱引用WeakReference、软引用SoftReference和虚引用PhantomReference。它们的区别也很明显,HardReference对象是即使虚拟机内存吃紧抛出OOM也不会导致这一引用的对象被回收,而WeakReference等更适合于一些数量不多,但体积稍微庞大的对象,在这四个引用中,它是最容易被垃圾回收的,而我们对于显示类似Android Market中每个应用的App Icon时可以考虑使用SoftReference来解决内存不至于快速回收,同时当内存短缺面临Java VM崩溃抛出OOM前时,软引用将会强制回收内存,最后的虚引用一般没有实际意义,仅仅观察GC的活动状态,对于测试比较实用同时必须和ReferenceQueue一起使用。对于一组数据,我们可以通过HashMap的方式来添加一组SoftReference对象来临时保留一些数据,同时对于需要反复通过网络获取的不经常改变的内容,可以通过本地的文件系统或数据库来存储缓存。
几个辅助类文件:
图片和文字的实体类
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; }}
view的缓存类
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; }}
自定义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; }}
adapter类的一些实现方式
1,imageView.setTag(imageUrl);标记此imageUrl的imageView 待没有此图片回调imageLoaded时 取得对应此imageUrl的ImageView(imageViewByTag)
这样是为了保证在回调函数时,listview去更新自己对应item
2,没有此图片时,异步加载类中的loadDrawable返回null 回调imageLoaded放入图片
3,有此图片时,通过loadDrawable取得drawable给cachedImage,放入图片
布局文件
<?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>
主activity
package cn.wangmeng.test;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.widget.ListView;public class AsyncListImage extends Activity {private ListView list; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); list=(ListView)findViewById(R.id.list); List<ImageAndText> dataArray=new ArrayList<ImageAndText>();// ImageAndText test=new ImageAndText("http://www.wangmeng.cn/images/logo.gif", "test");// ImageAndText test1=new ImageAndText("http://www.wangmeng.cn/images/ad/t1.gif", "test1");// ImageAndText test2=new ImageAndText("http://www.wangmeng.cn/images/ad/t3.gif", "test2"); ImageAndText test=new ImageAndText("http://img3.douban.com/lpic/s11082606.jpg", "test"); ImageAndText test1=new ImageAndText("http://img3.douban.com/lpic/s11181635.jpg", "test1"); ImageAndText test2=new ImageAndText("http://img5.douban.com/lpic/s11169899.jpg", "test2"); ImageAndText test3=new ImageAndText("http://img3.douban.com/lpic/s11192408.jpg", "test"); ImageAndText test4=new ImageAndText("http://img1.douban.com/lpic/s11192434.jpg", "test"); ImageAndText test5=new ImageAndText("http://img5.douban.com/lpic/s10324209.jpg", "test"); ImageAndText test6=new ImageAndText("http://img5.douban.com/lpic/s11181029.jpg", "test"); ImageAndText test7=new ImageAndText("http://img3.douban.com/lpic/s11218427.jpg", "test"); ImageAndText test8=new ImageAndText("http://img3.douban.com/lpic/s11162616.jpg", "test"); ImageAndText test9=new ImageAndText("http://img3.douban.com/lpic/s11082606.jpg", "test"); dataArray.add(test); dataArray.add(test1); dataArray.add(test2); dataArray.add(test3); dataArray.add(test4); dataArray.add(test5); dataArray.add(test6); dataArray.add(test7); dataArray.add(test8); dataArray.add(test9); ImageAndTextListAdapter adapter=new ImageAndTextListAdapter(this, dataArray, list); list.setAdapter(adapter); }}
自己动手实验吧 没问题 截图也看不出效果 主要总结下异步加载类到底如何运行的
补充:
关于代码中adapter类中的 super(activity, 0, imageAndTexts);
先来看官网的构造方法