首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

Android兑现ListView异步加载图片总结

2012-09-21 
Android实现ListView异步加载图片总结参考自 http://blog.csdn.net/wanglong0537/article/details/6334005

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 ConstructorsArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects)Constructor 选取ArrayAdapter(Context context, int textViewResourceId, List<T> objects)  是为了把list传来直接给ArrayAdapter填充了数据 textViewResourceId设为0(即省略此参数)

热点排行