Android ListView圖片異步加載顯示

openkk 12年前發布 | 76K 次閱讀 Android Android開發 移動開發

模擬android中的消息機制實現圖片的異步加載和動態顯示

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

        } } } }</pre>

        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; } }</pre>

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!