分享

Android ListView图片异步加载显示

 windli笔记 2012-03-16
001 package cn.jd3g.utils;
002   
003 import java.lang.ref.SoftReference;
004 import java.util.HashMap;
005 import java.util.LinkedHashMap;
006 import java.util.Map.Entry;
007   
008 import android.graphics.Bitmap;
009 import android.os.Handler;
010 import android.util.Log;
011 import android.widget.ImageView;
012   
013 /**
014  * 利用多线程异步加载图片并更新视图
015  
016  * @author xfzhang
017  
018  */
019 public final class AsynImageLoader {
020   
021     private LoaderThread thread;// 加载图片并发消息通知更新界面的线程
022     private HashMap<String, SoftReference<Bitmap>> imageCache;// 图片对象缓存,key:图片的url
023     private Handler handler;// 界面Activity的Handler对象
024   
025     public AsynImageLoader(Handler handler) {
026         imageCache = new HashMap<String, SoftReference<Bitmap>>();
027         this.handler = handler;
028     }
029   
030     /**
031      * 加载图片前显示到指定的ImageView中,图片的url保存在视图对象的Tag中
032      
033      * @param imageView
034      *            要显示图片的视图
035      * @param defaultBitmap
036      *            加载需要显示的提示正在加载的默认图片对象
037      */
038     public void loadBitmap(ImageView imageView, Bitmap defaultBitmap) {
039         // 图片所对应的url,这个值在加载图片过程中很可能会被改变
040         String url = (String) imageView.getTag();
041         if (imageCache.containsKey(url)) {// 判断缓存中是否有
042             SoftReference<Bitmap> softReference = imageCache.get(url);
043             Bitmap bitmap = softReference.get();
044             if (bitmap != null) {// 如果图片对象不为空,则可挂接更新视图,并返回
045                 imageView.setImageBitmap(bitmap);
046                 return;
047             } else {// 如果为空,需要将其从缓存中删除(其bitmap对象已被回收释放,需要重新加载)
048                 Log.e("TAG", "cache bitmap is null");
049                 imageCache.remove(url);
050             }
051         }
052         imageView.setImageBitmap(defaultBitmap);// 先显示一个提示正在加载的图片
053         if (thread == null) {// 加载线程不存在,线程还未启动,需要新建线程并启动
054             thread = new LoaderThread(imageView, url);
055             thread.start();
056         } else {// 如果存在,就调用线程对象去加载
057             thread.load(imageView, url);
058         }
059   
060     }
061   
062     /**
063      * 释放缓存中所有的Bitmap对象,并将缓存清空
064      */
065     public void releaseBitmapCache() {
066         if (imageCache != null) {
067             for (Entry<String, SoftReference<Bitmap>> entry : imageCache.entrySet()) {
068                 Bitmap bitmap = entry.getValue().get();
069                 if (bitmap != null) {
070                     bitmap.recycle();// 释放bitmap对象
071                 }
072             }
073             imageCache.clear();
074         }
075     }
076   
077     /**
078      * 加载图片并显示的线程
079      */
080     private class LoaderThread extends Thread {
081   
082         LinkedHashMap<String, ImageView> mTaskMap;// 需要加载图片并显示的图片视图对象任务链
083         private boolean mIsWait;// 标识是线程是否处于等待状态
084   
085         public LoaderThread(ImageView imageView, String url) {
086             mTaskMap = new LinkedHashMap<String, ImageView>();
087             mTaskMap.put(url, imageView);
088         }
089   
090         /**
091          * 处理某个视图的更新显示
092          
093          * @param imageView
094          */
095         public void load(ImageView imageView, String url) {
096             mTaskMap.remove(imageView);// 任务链中可能有,得先删除
097             mTaskMap.put(url, imageView);// 将其添加到任务中
098             if (mIsWait) {// 如果线程此时处于等待得唤醒线程去处理任务队列中待处理的任务
099                 synchronized (this) {// 调用对象的notify()时必须同步
100                     this.notify();
101                 }
102             }
103         }
104   
105         @Override
106         public void run() {
107             while (mTaskMap.size() > 0) {// 当队列中有数据时线程就要一直运行,一旦进入就要保证其不会跳出循环
108                 mIsWait = false;
109                 final String url  = mTaskMap.keySet().iterator().next();
110                 final ImageView imageView = mTaskMap.remove(url);
111                 if (imageView.getTag() == url) {// 判断视图有没有复用(一旦ImageView被复用,其tag值就会修改变)
112                     final Bitmap bitmap = MyConnection.getBitmapByUrl(url);// 此方法应该是从网络或sd卡中加载
113                     try {
114                         Thread.sleep(1000);// 模拟网络加载数据时间
115                     } catch (InterruptedException e1) {
116                         e1.printStackTrace();
117                     }
118                     // 将加载的图片放入缓存map中
119                     imageCache.put(url, new SoftReference<Bitmap>(bitmap));
120                     if (url == imageView.getTag()) {// 再次判断视图有没有复用
121                         handler.post(new Runnable() {// 通过消息机制在主线程中更新UI
122                             @Override
123                             public void run() {
124                                 imageView.setImageBitmap(bitmap);
125                             }
126                         });
127                     }
128                 }
129                 if (mTaskMap.isEmpty()) {// 当任务队列中没有待处理的任务时,线程进入等待状态
130                     try {
131                         mIsWait = true;// 标识线程的状态,必须在wait()方法之前
132                         synchronized (this) {
133                             this.wait();// 保用线程进入等待状态,直到有新的任务被加入时通知唤醒
134                         }
135                     } catch (InterruptedException e) {
136                         e.printStackTrace();
137                     }
138                 }
139             }
140         }
141     }
142 }
01 private class ProductListAdapter extends BaseAdapter {
02   
03         private AsynImageLoader mImageAsynLoader;
04   
05         public ProductListAdapter() {
06             mImageAsynLoader = new AsynImageLoader(mHandler);
07         }
08   
09         @Override
10         public int getCount() {
11             int size = Math.min(mLastItemViewIndex + 1, mDataList.size());
12             mLastItemViewIndex = size - 1;
13             return size;
14         }
15   
16         @Override
17         public Object getItem(int position) {
18             return mDataList.get(position);
19         }
20   
21         @Override
22         public long getItemId(int position) {
23             return position;
24         }
25   
26         @Override
27         public View getView(int position, View convertView, ViewGroup parent) {
28             if (convertView == null) {
29                 convertView = getLayoutInflater().inflate(R.layout.product_list_item,
30                         null);
31             }
32             ImageView imageView = (ImageView) convertView
33                     .findViewById(R.id.iv_item_product_image);
34             Map<String, String> map = mDataList.get(position);
35 //存放图片所对应的url
36             imageView.setTag(map.get("product_pic_address"));
37             mImageAsynLoader.loadBitmap(imageView, mDefautBitmap);
38             return convertView;
39         }
40     }

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多