高效率下載圖片——防止內存溢出

在應用中常常須要下載不少的圖片,所以,寫好圖片下載部分的代碼很是關鍵。很差的代碼很容易建立太多的對象,致使常常執行GC,接着就出現了ANR;也很容易致使內存溢出OOM。javascript

 

如今,我從防止ANR和OOM的角度寫下載圖片的代碼。再來分析一下需求,當我須要爲圖片列表下載不少張圖片時,我指望圖片是有順序地一張一張顯示,而不是開啓不少線程同時下載多張圖片(注意:這樣也會影響每一個線程的執行速度)。java


  1. import java.util.ArrayList;  
  2. import java.util.HashMap;  
  3. import java.util.List;  
  4. import java.util.Map;  
  5.   
  6. import android.graphics.Bitmap;  
  7. import android.graphics.BitmapFactory;  
  8. import android.os.Handler;  
  9. import android.os.Message;  
  10.   
  11. public class ImageDownloadThread extends Thread {  
  12.     //單例類  
  13.     private ImageDownloadThread() {}  
  14.     private static ImageDownloadThread imageDownloadThread = null;  
  15.     public static ImageDownloadThread getInstance() {  
  16.         if (imageDownloadThread == null) {  
  17.             imageDownloadThread = new ImageDownloadThread();  
  18.             imageDownloadThread.start();//建立後馬上運行  
  19.         }  
  20.         return imageDownloadThread;  
  21.     }  
  22.       
  23.     //緩存下載圖片  
  24.     private Map<String, String> cache = new HashMap<String, String>();//KEY:圖片URL;VALUE:下載後的圖片路徑  
  25.     public boolean isDownload(String imageUrl) {  
  26.         return cache.containsKey(imageUrl);  
  27.     }  
  28.     public Bitmap downloadWithCache(ImageDownloadItem item) {  
  29.         if (cache.containsKey(item.imageUrl)) {  
  30.             Bitmap bitmap = BitmapFactory.decodeFile(cache.get(item.imageUrl));  
  31.             return bitmap;  
  32.         } else {  
  33.             addDownloadItem(item);  
  34.         }  
  35.         return null;  
  36.     }  
  37.     public void downloadWithoutCache(ImageDownloadItem item) {  
  38.         addDownloadItem(item);  
  39.     }  
  40.   
  41.     //下載隊列  
  42.     private List<ImageDownloadItem> queue = new ArrayList<ImageDownloadItem>();  
  43.     private synchronized void addDownloadItem(ImageDownloadItem item) {  
  44.         queue.add(item);  
  45.         this.notify();//添加了下載項就激活本線程  
  46.     }  
  47.   
  48.     @Override  
  49.     public void run() {  
  50.         while(true) {  
  51.             while(queue.size() > ) {  
  52.                 ImageDownloadItem item = queue.remove();  
  53.                 String imagePath = downloadImage(item.imageUrl);  
  54.                 //緩存圖片路徑  
  55.                 cache.put(item.imageUrl, imagePath);  
  56.   
  57.                 if (item.callback != null) {//須要執行回調來顯示圖片  
  58.                     item.imagePath = imagePath;  
  59.   
  60.                     //交由UI線程處理  
  61.                     Message msg = handler.obtainMessage();  
  62.                     msg.obj = item;  
  63.                     handler.sendMessage(msg);  
  64.                 }  
  65.             }  
  66.             try {  
  67.                 synchronized(this) {  
  68.                     this.wait();//沒有下載項時等待  
  69.                 }  
  70.             } catch (InterruptedException e) {  
  71.                 e.printStackTrace();  
  72.             }  
  73.         }  
  74.     }  
  75.       
  76.     private String downloadImage(String imageUrl) {  
  77.         //TODO  
  78.         //不提供該方法代碼  
  79.         //下載部分應該有專門下載文件的類(如:FileDownloadUtil.download(imageUrl))  
  80.         return "";  
  81.     }  
  82.   
  83.     private Handler handler = new Handler() {  
  84.         @Override  
  85.         public void handleMessage(Message msg) {  
  86.             ImageDownloadItem item = (ImageDownloadItem)msg.obj;  
  87.             Bitmap bitmap = BitmapFactory.decodeFile(item.imagePath);  
  88.             item.callback.update(bitmap, item.imageUrl);  
  89.         }  
  90.     };  
  91.   
  92.     public static class ImageDownloadItem {  
  93.         public String imageUrl;//須要下載的圖片URL  
  94.         public String imagePath;//下載的後圖片路徑  
  95.         public ImageDownloadCallback callback;//回調方法  
  96.     }  
  97.       
  98.     public static interface ImageDownloadCallback {  
  99.         //策略模式,由子類實現  
  100.         public void update(Bitmap bitmap, String imageUrl);  
  101.     }  
  102. }  

 

下面是使用的代碼片斷android

 

Java代碼    收藏代碼
  1. public View getView(int position, View convertView, ViewGroup vg) {  
  2.         final ImageView imageView;  
  3.         if (convertView != null) {  
  4.             imageView = (ImageView)convertView;  
  5.         } else {  
  6.             imageView = new ImageView(this);  
  7.         }  
  8.         //在實際應用中imageUrl值是不一樣的  
  9.         String imageUrl = "http://www.nxnet.net/yule/yljj/200710/W020071008388975463611.jpg";  
  10.         imageView.setTag(imageUrl);  
  11.           
  12.         //設置下載項  
  13.         ImageDownloadItem item = new ImageDownloadItem();  
  14.         item.imageUrl = imageUrl;  
  15.         //若是是無需顯示圖片的狀況(如預下載),無需設置item.callback,即讓item.callback = null  
  16.         item.callback = new ImageDownloadCallback() {  
  17.             @Override  
  18.             public void update(Bitmap bitmap, String imageUrl) {  
  19.                 ImageView imageViewByTag = (ImageView)imageView.findViewWithTag(imageUrl);  
  20.                 if (imageViewByTag != null) imageViewByTag.setImageBitmap(bitmap);  
  21.             }  
  22.         };  
  23.           
  24.         ImageDownloadThread imageDownloadThread = ImageDownloadThread.getInstance();  
  25.         Bitmap bitmap = imageDownloadThread.downloadWithCache(item);  
  26.         if (bitmap != null) {//從緩存中取到  
  27.             imageView.setImageBitmap(bitmap);  
  28.         }  
  29.         return imageView;  
  30.     }  
相關文章
相關標籤/搜索