灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:4414回复:0

图片的异步加载

楼主#
更多 发布于:2012-09-06 13:52


[java] package cn.jd3g.utils;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;

import Android.graphics.Bitmap;
import Android.os.Handler;
import Android.util.Log;
import Android.widget.ImageView;

/**
* 利用多线程异步加载图片并更新视图
*
* @author xfzhang
*
*/
public final class AsynImageLoader {

    private LoaderThread thread;// 加载图片并发消息通知更新界面的线程  
    private HashMap<String, SoftReference<Bitmap>> imageCache;// 图片对象缓存,key:图片的url  
    private Handler handler;// 界面Activity的Handler对象  

    public AsynImageLoader(Handler handler) {
        imageCache = new HashMap<String, SoftReference<Bitmap>>();
        this.handler = handler;
    }

    /**
     * 加载图片前显示到指定的ImageView中,图片的url保存在视图对象的Tag中
     *
     * @param imageView
     *            要显示图片的视图
     * @param defaultBitmap
     *            加载需要显示的提示正在加载的默认图片对象
     */
    public void loadBitmap(ImageView imageView, Bitmap defaultBitmap) {
        // 图片所对应的url,这个值在加载图片过程中很可能会被改变  
        String url = (String) imageView.getTag();
        if (imageCache.containsKey(url)) {// 判断缓存中是否有  
            SoftReference<Bitmap> softReference = imageCache.get(url);
            Bitmap bitmap = softReference.get();
            if (bitmap != null) {// 如果图片对象不为空,则可挂接更新视图,并返回  
                imageView.setImageBitmap(bitmap);
                return;
            } else {// 如果为空,需要将其从缓存中删除(其bitmap对象已被回收释放,需要重新加载)  
                Log.e("TAG", "cache bitmap is null");
                imageCache.remove(url);
            }
        }
        imageView.setImageBitmap(defaultBitmap);// 先显示一个提示正在加载的图片  
        if (thread == null) {// 加载线程不存在,线程还未启动,需要新建线程并启动  
            thread = new LoaderThread(imageView, url);
            thread.start();
        } else {// 如果存在,就调用线程对象去加载  
            thread.load(imageView, url);
        }

    }

    /**
     * 释放缓存中所有的Bitmap对象,并将缓存清空
     */
    public void releaseBitmapCache() {
        if (imageCache != null) {
            for (Entry<String, SoftReference<Bitmap>> entry : imageCache.entrySet()) {
                Bitmap bitmap = entry.getValue().get();
                if (bitmap != null) {
                    bitmap.recycle();// 释放bitmap对象  
                }
            }
            imageCache.clear();
        }
    }

    /**
     * 加载图片并显示的线程
     */
    private class LoaderThread extends Thread {

        LinkedHashMap<String, ImageView> mTaskMap;// 需要加载图片并显示的图片视图对象任务链  
        private boolean mIsWait;// 标识是线程是否处于等待状态  

        public LoaderThread(ImageView imageView, String url) {
            mTaskMap = new LinkedHashMap<String, ImageView>();
            mTaskMap.put(url, imageView);
        }

        /**
         * 处理某个视图的更新显示
         *
         * @param imageView
         */
        public void load(ImageView imageView, String url) {
            mTaskMap.remove(imageView);// 任务链中可能有,得先删除  
            mTaskMap.put(url, imageView);// 将其添加到任务中  
            if (mIsWait) {// 如果线程此时处于等待得唤醒线程去处理任务队列中待处理的任务  
                synchronized (this) {// 调用对象的notify()时必须同步  
                    this.notify();
                }
            }
        }

        @Override
        public void run() {
            while (mTaskMap.size() > 0) {// 当队列中有数据时线程就要一直运行,一旦进入就要保证其不会跳出循环  
                mIsWait = false;
                final String url  = mTaskMap.keySet().iterator().next();
                final ImageView imageView = mTaskMap.remove(url);
                if (imageView.getTag() == url) {// 判断视图有没有复用(一旦ImageView被复用,其tag值就会修改变)  
                    final Bitmap bitmap = MyConnection.getBitmapByUrl(url);// 此方法应该是从网络或sd卡中加载  
                    try {
                        Thread.sleep(1000);// 模拟网络加载数据时间  
                    } catch (interruptedException e1) {
                        e1.printStackTrace();
                    }
                    // 将加载的图片放入缓存map中  
                    imageCache.put(url, new SoftReference<Bitmap>(bitmap));
                    if (url == imageView.getTag()) {// 再次判断视图有没有复用  
                        handler.post(new Runnable() {// 通过消息机制在主线程中更新UI  
                            @Override
                            public void run() {
                                imageView.setImageBitmap(bitmap);
                            }
                        });
                    }
                }
                if (mTaskMap.isEmpty()) {// 当任务队列中没有待处理的任务时,线程进入等待状态  
                    try {
                        mIsWait = true;// 标识线程的状态,必须在wait()方法之前  
                        synchronized (this) {
                            this.wait();// 保用线程进入等待状态,直到有新的任务被加入时通知唤醒  
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
package cn.jd3g.utils;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import Android.graphics.Bitmap;
import Android.os.Handler;
import Android.util.Log;
import Android.widget.ImageView;
/**
* 利用多线程异步加载图片并更新视图
*
* @author xfzhang
*
*/
public final class AsynImageLoader {
private LoaderThread thread;// 加载图片并发消息通知更新界面的线程
private HashMap<String, SoftReference<Bitmap>> imageCache;// 图片对象缓存,key:图片的url
private Handler handler;// 界面Activity的Handler对象
public AsynImageLoader(Handler handler) {
  imageCache = new HashMap<String, SoftReference<Bitmap>>();
  this.handler = handler;
}
/**
  * 加载图片前显示到指定的ImageView中,图片的url保存在视图对象的Tag中
  *
  * @param imageView
  *            要显示图片的视图 www.atcpu.com
  * @param defaultBitmap
  *            加载需要显示的提示正在加载的默认图片对象
  */
public void loadBitmap(ImageView imageView, Bitmap defaultBitmap) {
  // 图片所对应的url,这个值在加载图片过程中很可能会被改变
  String url = (String) imageView.getTag();
  if (imageCache.containsKey(url)) {// 判断缓存中是否有
   SoftReference<Bitmap> softReference = imageCache.get(url);
   Bitmap bitmap = softReference.get();
   if (bitmap != null) {// 如果图片对象不为空,则可挂接更新视图,并返回
    imageView.setImageBitmap(bitmap);
    return;
   } else {// 如果为空,需要将其从缓存中删除(其bitmap对象已被回收释放,需要重新加载)
    Log.e("TAG", "cache bitmap is null");
    imageCache.remove(url);
   }
  }
  imageView.setImageBitmap(defaultBitmap);// 先显示一个提示正在加载的图片
  if (thread == null) {// 加载线程不存在,线程还未启动,需要新建线程并启动
   thread = new LoaderThread(imageView, url);
   thread.start();
  } else {// 如果存在,就调用线程对象去加载
   thread.load(imageView, url);
  }
}
/**
  * 释放缓存中所有的Bitmap对象,并将缓存清空
  */
public void releaseBitmapCache() {
  if (imageCache != null) {
   for (Entry<String, SoftReference<Bitmap>> entry : imageCache.entrySet()) {
    Bitmap bitmap = entry.getValue().get();
    if (bitmap != null) {
     bitmap.recycle();// 释放bitmap对象
    }
   }
   imageCache.clear();
  }
}
/**
  * 加载图片并显示的线程
  */
private class LoaderThread extends Thread {
  LinkedHashMap<String, ImageView> mTaskMap;// 需要加载图片并显示的图片视图对象任务链
  private boolean mIsWait;// 标识是线程是否处于等待状态
  public LoaderThread(ImageView imageView, String url) {
   mTaskMap = new LinkedHashMap<String, ImageView>();
   mTaskMap.put(url, imageView);
  }
  /**
   * 处理某个视图的更新显示
   *
   * @param imageView
   */
  public void load(ImageView imageView, String url) {
   mTaskMap.remove(imageView);// 任务链中可能有,得先删除
   mTaskMap.put(url, imageView);// 将其添加到任务中
   if (mIsWait) {// 如果线程此时处于等待得唤醒线程去处理任务队列中待处理的任务
    synchronized (this) {// 调用对象的notify()时必须同步
     this.notify();
    }
   }
  }
  @Override
  public void run() {
   while (mTaskMap.size() > 0) {// 当队列中有数据时线程就要一直运行,一旦进入就要保证其不会跳出循环
    mIsWait = false;
    final String url  = mTaskMap.keySet().iterator().next();
    final ImageView imageView = mTaskMap.remove(url);
    if (imageView.getTag() == url) {// 判断视图有没有复用(一旦ImageView被复用,其tag值就会修改变)
     final Bitmap bitmap = MyConnection.getBitmapByUrl(url);// 此方法应该是从网络或sd卡中加载
     try {
      Thread.sleep(1000);// 模拟网络加载数据时间
     } catch (InterruptedException e1) {
      e1.printStackTrace();
     }
     // 将加载的图片放入缓存map中
     imageCache.put(url, new SoftReference<Bitmap>(bitmap));
     if (url == imageView.getTag()) {// 再次判断视图有没有复用
      handler.post(new Runnable() {// 通过消息机制在主线程中更新UI
       @Override
       public void run() {
        imageView.setImageBitmap(bitmap);
       }
      });
     }
    }
    if (mTaskMap.isEmpty()) {// 当任务队列中没有待处理的任务时,线程进入等待状态
     try {
      mIsWait = true;// 标识线程的状态,必须在wait()方法之前
      synchronized (this) {
       this.wait();// 保用线程进入等待状态,直到有新的任务被加入时通知唤醒
      }
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   }
  }
}
}自定义的adapter
[java] private class ProductListAdapter extends BaseAdapter {

        private AsynImageLoader mImageAsynLoader;

        public ProductListAdapter() {
            mImageAsynLoader = new AsynImageLoader(mHandler);
        }

        @Override
        public int getCount() {
            int size = Math.min(mLastItemViewIndex + 1, mDataList.size());
            mLastItemViewIndex = size - 1;
            return size;
        }

        @Override
        public Object getItem(int position) {
            return mDataList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = getLayoutInflater().inflate(R.layout.product_list_item,
                        null);
            }
            ImageView imageView = (ImageView) convertView
                    .findViewById(R.id.iv_item_product_image);
            Map<String, String> map = mDataList.get(position);
//存放图片所对应的url  
            imageView.setTag(map.get("product_pic_address"));
            mImageAsynLoader.loadBitmap(imageView, mDefautBitmap);
            return convertView;
        }
    }
private class ProductListAdapter extends BaseAdapter {
  private AsynImageLoader mImageAsynLoader;
  public ProductListAdapter() {
   mImageAsynLoader = new AsynImageLoader(mHandler);
  }
  @Override
  public int getCount() {
   int size = Math.min(mLastItemViewIndex + 1, mDataList.size());
   mLastItemViewIndex = size - 1;
   return size;
  }
  @Override
  public Object getItem(int position) {
   return mDataList.get(position);
  }
  @Override
  public long getItemId(int position) {
   return position;
  }
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   if (convertView == null) {
    convertView = getLayoutInflater().inflate(R.layout.product_list_item,
      null);
   }
   ImageView imageView = (ImageView) convertView
     .findViewById(R.id.iv_item_product_image);
   Map<String, String> map = mDataList.get(position);
//存放图片所对应的url
   imageView.setTag(map.get("product_pic_address"));
   mImageAsynLoader.loadBitmap(imageView, mDefautBitmap);
   return convertView;
  }
}



喜欢0 评分0
游客

返回顶部