圖片的異步加載

[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.aiwalls.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;
  }
 }

 
摘自 agods–足跡
 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。