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);

先来看官网的构造方法

Public Constructors
ArrayAdapter( Context context, int textViewResourceId)
Constructor
ArrayAdapter( Context context, int resource, int textViewResourceId)
Constructor
ArrayAdapter( Context context, int textViewResourceId, T[] objects)
Constructor
ArrayAdapter( Context context, int resource, int textViewResourceId, T[] objects)
Constructor
ArrayAdapter( Context context, int textViewResourceId, List<T> objects)
Constructor
ArrayAdapter( Context context, int resource, int textViewResourceId, List<T> objects)
Constructor
 
选取 ArrayAdapter( Context context, int textViewResourceId, List<T> objects)  是为了把list传来直接给ArrayAdapter填充了数据 textViewResourceId设为0(即省略此参数)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值