簡體   English   中英

Android - 存儲從網絡下載的圖像

[英]Android - Storing images downloaded from the web

我有一個問題是關於我是否應該(以及如何)存儲從網絡加載的圖像。 假設我從我的Android應用程序調用Web服務。 在這個Web服務中,我獲得了Web上圖像的URL。 我下載並在ListView中列表項的左側顯示此圖像。 我的問題是,我應該使用什么方法來存儲圖像? 我是不是該:

  1. 將其保存到SD卡,檢查創建ListView時是否存在(在后續請求中)並根據需要重新下載(偶爾更新圖像,以防它發生變化)。
  2. 使用Context.getCacheDir()將其存儲在緩存中,但可能會被迫更頻繁地重新下載,因為我無法依賴緩存中的圖像。
  3. 始終下載它,從不存儲圖像。

圖像文件本身相當小,但我希望一些用戶可以下載/存儲這些小圖像。 哪種方法效果最好,和/或什么是首選方法?

作為一個附帶問題,我應該首先加載我的ListView中的所有圖像(並且可能會鎖定UI一段時間)或者異步加載它們,但同時顯示占位符圖形(可能更“丑陋”)? 這里的標准是什么?

關於存儲位置:答案取決於下載的內容和數量。 然后你做出選擇。

例如:如果您正在下載臨時的,較少的(較少的遠程讀取)和大小(較少的內存)並且是Activity的本地內容,那么您應該考慮使用SoftReferences將圖像保存在內存中。 SoftReferences可以導致重新獲取,但由於項目數量很少,因此應該可以負擔得起。

但是,如果要下載的項目數超過某個閾值(意味着更多的提取和內存),則應考慮通過緩存它們來減少提取以及運行時內存消耗。 在這里,您可以選擇將它們保存在Sdcard上或臨時存儲(應用程序本地的緩存目錄)上。 對於小而且僅在應用程序的上下文中具有意義的項目(例如縮略圖),用戶通常不會在應用程序之外使用它。 因此,您可以將這些內容存儲在緩存目錄中。 使用它們最好的部分是你不必清理混亂。 它會自動處理。 但它可能導致重新獲取。

但是,如果下載的項目很大並且可以獨立於應用程序的上下文之外,例如圖片,視頻,音頻剪輯,那么SD卡應該是您的選擇。 您還應該閱讀: 處理大型位圖以避免在BitmapFactory.decodeStream(..)期間出現OOM錯誤

請注意,您還可以檢查使用數據庫是否可以在此處提供幫助。 看到這個

在ListView中延遲加載項時的一些注意事項:您應該在后台加載而不阻止UI線程。您應該考慮在下載項目時顯示臨時圖像。 這在許多本機應用程序中很明顯。 有關延遲加載的示例實現, 請參閱此內容 此外,對於大型列表,您可以實現SlowAdapter模式(檢查API演示)。 當列表滾動時,它基本上會停止下載。

示例項目可以幫助您:

Romain Guy的Shelves項目使用兩級緩存,其中他使用內存緩存(包含SoftReferences的HashMap)和Sdcard上的存儲。 在這里瀏覽源代碼

還有一些開源庫,Mark Murphy寫的(CWAC)和DroidFu可以在這里提供幫助。

祝好運!

關於你的“副問題” - 我認為異步加載它們將是首選行為,特別是因為你需要考慮網絡事務,它可能不僅僅是“鎖定UI一段時間”,而是“鎖定”用戶界面永久“以防它永遠不會加載。

但是,如果您認為這種行為很難看,您可以設置一個計時器(1或2秒),使一些圖像有機會加載,如果它們全部已加載或計時器已過期,請繼續顯示UI無論如何使用占位符圖像並讓其余部分異步加載。 無論如何,這將是防止永久鎖定的方法。

至於問題的第一部分,我認為它在某種程度上取決於您正在顯示的圖像的上下文和類型。 但是,對於大多數Web資產,我認為#2將是首選方法,因為您當然不希望在同一會話中多次下載,但您可能也不想占用永久存儲。

關於你的“副問題” - 我認為異步加載它們將是首選行為,特別是因為你需要考慮網絡事務,它可能不僅僅是“鎖定UI一段時間”,而是“鎖定”用戶界面永久“以防它永遠不會加載。

為了避免這種情況,如果我們通過droid-fu討論WebImageView ,你可以將ImageLoader.java的initialize()函數更改為

    static int alive=-1;
   public static synchronized void initialize(Context context) {

        if (executor == null) {        
           executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);           
       }
        else if(alive==executor.getActiveCount()){
               executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);
           }
       alive=executor.getActiveCount();
       if (imageCache == null) {
           imageCache = new ImageCacheHope(context, 25, 5);
       }
   }

我寫了一個Android Image Manager來透明地處理緩存(內存和磁盤)。 代碼在Github上https://github.com/felipecsl/Android-ImageManager

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM