一、ImageView非同步載入類
package com.busap.netutils;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 lizhen * */public final class AsynImageLoader {private LoaderThread thread;// 載入圖片並發訊息通知更新介面的線程private HashMap<String, SoftReference<Bitmap>> imageCache;// 圖片對象緩衝,key:圖片的urlprivate 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();}}}@Overridepublic 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@Overridepublic void run() {imageView.setImageBitmap(bitmap);}});}}if (mTaskMap.isEmpty()) {// 當任務隊列中沒有待處理的任務時,線程進入等待狀態try {mIsWait = true;// 標識線程的狀態,必須在wait()方法之前synchronized (this) {this.wait();// 保用線程進入等待狀態,直到有新的任務被加入時通知喚醒}} catch (InterruptedException e) {e.printStackTrace();}}}}}}
二、使用
Handler handler;AsynImageLoader mImageAsynLoader;mImageAsynLoader.loadBitmap(discount_icon,defaultBitmap);