高效率下載圖片——防止記憶體溢出

來源:互聯網
上載者:User

在應用中經常需要下載很多的圖片,因此,寫好圖片下載部分的代碼非常關鍵。不好的代碼很容易建立太多的對象,導致經常執行GC,接著就出現了ANR;也很容易導致記憶體溢出OOM。
 
現在,我從防止ANR和OOM的角度寫下載圖片的代碼。再來分析一下需求,當我需要為圖片列表下載很多張圖片時,我期望圖片是有順序地一張一張顯示,而不是開啟很多線程同時下載多張圖片(注意:這樣也會影響每個線程的執行速度)。
 
 
Java代碼 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.os.Handler; 
import android.os.Message; 
 
public class ImageDownloadThread extends Thread { 
    //單例類 
    private ImageDownloadThread() {} 
    private static ImageDownloadThread imageDownloadThread = null; 
    public static ImageDownloadThread getInstance() { 
        if (imageDownloadThread == null) { 
            imageDownloadThread = new ImageDownloadThread(); 
            imageDownloadThread.start();//建立後立刻運行 
        } 
        return imageDownloadThread; 
    } 
     
    //緩衝下載圖片 
    private Map<String, String> cache = new HashMap<String, String>();//KEY:圖片URL;VALUE:下載後的圖片路徑 
    public boolean isDownload(String imageUrl) { 
        return cache.containsKey(imageUrl); 
    } 
    public Bitmap downloadWithCache(ImageDownloadItem item) { 
        if (cache.containsKey(item.imageUrl)) { 
            Bitmap bitmap = BitmapFactory.decodeFile(cache.get(item.imageUrl)); 
            return bitmap; 
        } else { 
            addDownloadItem(item); 
        } 
        return null; 
    } 
    public void downloadWithoutCache(ImageDownloadItem item) { 
        addDownloadItem(item); 
    } 
 
    //下載隊列 
    private List<ImageDownloadItem> queue = new ArrayList<ImageDownloadItem>(); 
    private synchronized void addDownloadItem(ImageDownloadItem item) { 
        queue.add(item); 
        this.notify();//添加了下載項就啟用本線程 
    } 
 
    @Override 
    public void run() { 
        while(true) { 
            while(queue.size() > 0) { 
                ImageDownloadItem item = queue.remove(0); 
                String imagePath = downloadImage(item.imageUrl); 
                //緩衝圖片路徑 
                cache.put(item.imageUrl, imagePath); 
 
                if (item.callback != null) {//需要執行回調來顯示圖片 
                    item.imagePath = imagePath; 
 
                    //交由UI線程處理 
                    Message msg = handler.obtainMessage(); 
                    msg.obj = item; 
                    handler.sendMessage(msg); 
                } 
            } 
            try { 
                synchronized(this) { 
                    this.wait();//沒有下載項時等待 
                } 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 
     
    private String downloadImage(String imageUrl) { 
        //TODO 
        //不提供該方法代碼 
        //下載部分應該有專門下載檔案的類(如:FileDownloadUtil.download(imageUrl)) 
        return ""; 
    } 
 
    private Handler handler = new Handler() { 
        @Override 
        public void handleMessage(Message msg) { 
            ImageDownloadItem item = (ImageDownloadItem)msg.obj; 
            Bitmap bitmap = BitmapFactory.decodeFile(item.imagePath); 
            item.callback.update(bitmap, item.imageUrl); 
        } 
    }; 
 
    public static class ImageDownloadItem { 
        public String imageUrl;//需要下載的圖片URL 
        public String imagePath;//下載的後圖片路徑 
        public ImageDownloadCallback callback;//回調方法 
    } 
     
    public static interface ImageDownloadCallback { 
        //策略模式,由子類實現 
        public void update(Bitmap bitmap, String imageUrl); 
    } 

 
下面是使用的程式碼片段
 
Java代碼 
public View getView(int position, View convertView, ViewGroup vg) { 
        final ImageView imageView; 
        if (convertView != null) { 
            imageView = (ImageView)convertView; 
        } else { 
            imageView = new ImageView(this); 
        } 
        //在實際應用中imageUrl值是不同的 
        String imageUrl = "http://www.bkjia.com/uploadfile/2011/0919/20110919010659183.jpg"; 
        imageView.setTag(imageUrl); 
         
        //設定下載項 
        ImageDownloadItem item = new ImageDownloadItem(); 
        item.imageUrl = imageUrl; 
        //如果是無需顯示圖片的情況(如預下載),無需設定item.callback,即讓item.callback = null 
        item.callback = new ImageDownloadCallback() { 
            @Override 
            public void update(Bitmap bitmap, String imageUrl) { 
                ImageView imageViewByTag = (ImageView)imageView.findViewWithTag(imageUrl); 
                if (imageViewByTag != null) imageViewByTag.setImageBitmap(bitmap); 
            } 
        }; 
         
        ImageDownloadThread imageDownloadThread = ImageDownloadThread.getInstance(); 
        Bitmap bitmap = imageDownloadThread.downloadWithCache(item); 
        if (bitmap != null) {//從緩衝中取到 
            imageView.setImageBitmap(bitmap); 
        } 
        return imageView; 
    } 

作者“程式人生”
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.