2014-02-16 43 views
2

我有這個ImageAdapter爲Android的ListView控件:爲什麼Android ImageAdapter不能加載圖片?

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    View view = null; 
    RelativeLayout relativeLayout = null; 
    Offer currentOffer = mOffersList.get(position); 

    if (convertView == null) { // create a new view if no recycling 
           // available 
     // Make up a new view 
     LayoutInflater inflater = (LayoutInflater) mContext 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     view = inflater.inflate(R.layout.offer_list_item, null); 
     relativeLayout = (RelativeLayout) view 
       .findViewById(R.id.offerImage); 

    } else { 
     view = (View) convertView; 
     relativeLayout = (RelativeLayout) view 
       .findViewById(R.id.offerImage); 
     setBackgroundDrawable(relativeLayout, null); 

    } 

    String imageUrl = ""; 
    imageUrl = currentOffer.getImageUrl().toString(); 

    Bitmap bitmap = imageCache.get(imageUrl); 

    if (bitmap != null) { 
     Drawable dr = new BitmapDrawable(mContext.getResources(), bitmap); 
     setBackgroundDrawable(relativeLayout, dr); 
    } else { 
     if (!downloadingImageUrls.contains(imageUrl)) { 
      downloadingImageUrls.add(imageUrl); 
      new DownloadImageAsyncTask().execute(imageUrl); 
     } 
    } 

    return view; 
} 

這:

class DownloadImageAsyncTask extends AsyncTask<String, Void, Void> { 
     @Override 
     protected Void doInBackground(String... params) { 
      String imageUrl = params[0]; 
      try { 
       Bitmap bitmap = BitmapFactory 
         .decodeStream((InputStream) new URL(imageUrl) 
           .getContent()); 
       imageCache.put(imageUrl, bitmap); 

      } catch (IOException e) { 
       Log.e("DownloadImageAsyncTask", "Error reading bitmap" + e); 
      } 
      downloadingImageUrls.remove(imageUrl); 
      return null; 
     } 

     @Override 
     protected void onPostExecute(Void result) { 
      notifyDataSetChanged(); 
     } 
    } 

爲什麼所有一起加載列表中的項目?它不是異步的,但不是一個一個。全部一起。

我該如何加載它呢?

爲什麼這個代碼更高效?

// better 
public class DownloadImageAsyncTask2 extends 
     AsyncTask<String, Void, Bitmap> { 
    private final ImageView imageView; 

    public DownloadImageAsyncTask2(ImageView imageView) { 
     this.imageView = imageView; 
    } 

    @Override 
    protected void onPreExecute() { 
     Log.i("DownloadImageAsyncTask", "Starting image download task..."); 
    } 

    @Override 
    protected Bitmap doInBackground(String... params) { 
     try { 
      return BitmapFactory.decodeStream((InputStream) new URL(
        params[0]).getContent()); 
     } catch (IOException e) { 
      Log.e("DownloadImageAsyncTask", "Error reading bitmap" + e); 
     } 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Bitmap bitmap) { 
     if (bitmap != null) { 
      imageView.setImageBitmap(bitmap); 
     } 
    } 
} 
+0

確保在異步任務中使用WeakReference來訪問ImageView,並檢查ImageView引用是否仍然有效,否則您將持續使用Context引用的時間超過所需時間。另外,如果ImageView已經從窗口中分離出來並被遺忘,那麼調用'setImageBitmap'沒有意義。 – dcow

+0

另外,爲什麼你斷言第二個異步任務比第一個更好,我不一定會認爲它更有效,尤其是如果你在每次ImageView失去一個先前加載的引用時重新加載圖像(即每次配置更改)。 – dcow

+0

哦,我認爲我看到了斷言的性質,第二種方法只會使有問題的視圖無效,並且不要求ListView通過重新創建所有視圖來「重新裝載」所有數據。但是,您可以重寫'notifyDataSetChanged()'來僅執行必要的操作。我相信,默認會重新加載視圖。 – dcow

回答

2

要回答您的第一個問題,您所寫的任何適配器都與它的名稱完全相同;這是一個適配器。它允許您將數據轉換爲AdapterView中顯示的視圖。強迫所有意見「懶惰地加載」是毫無意義的,坦率地說,出於幾個原因,不應這樣做。

  1. 也許你已經預取了你的所有圖片,並且不需要延遲加載。也許他們甚至只是來自資源,並不需要特別處理。
  2. 它如何知道從何處延遲加載圖像(數據庫,內存映射,文件,網絡資源,其他Android服務等)?這是您在編寫適配器時的工作。

您可能會認爲適配器子類具有loadLazily(Uri image, ImageView view)函數會更好。如果是這樣,爲什麼不自己劃分AbsAdapter並將其添加或向AOSP提交補丁。然而,我懷疑你會發現,即使是像這樣的功能應該包含在適配器的一部分中也是如此。儘管在Android中依靠系統進行數據管理有多正常,但以有效的方式管理數據的確是您的工作。

要回答關於您提出的兩種延遲加載方法的其他問題,區別在於第一種方法會導致AdapterView重新加載其所有視圖,而在第二種方法中,您只是使視圖無效加載圖像。

我實際上並不認同第二種方法在整體上「更好」,因爲每次配置更改或進程死亡並且視圖需要重新加載時,您需要通過網絡或文件系統進行新的調用加載你的圖片。如果像在第一種方法中那樣緩存它們,那麼至少可以避免通過配置更改來重新加載所有圖像。如果你寫了一個單獨的圖像加載服務,它運行在它自己的進程中(不是我推薦的),你也可以避免第二種情況(你的默認進程被殺死)。

問題是,您負責加載您的圖片,而不是Android。如果您希望爲您完成,請查看這些優秀的圖像加載或android的其他一般資源採集庫:Local image caching solution for Android: Square Picasso vs Universal Image Loader。我以前親自使用過Universal-Image-Loader,並承認它的功能與廣告一致。但是,它會將所有圖像緩存到外部存儲器,這可能不適合您。

1

listview可以爲其onMeasure中的所有項調用getView(參見listView.java中的measureHeightOfChildren)。 因此,使用此getView,它會加載所有圖像。如果要加載得很懶,需要在其他地方加載圖像:讓視圖在需要時(onDraw)向圖像請求一個管理器(它將異步加載它們)。

notifyDataSetChanged()更新所有listview(意味着回收視圖,調用getView ...),imageView.setImageBitmap將只更新ImageView,因此這是一個更好的主意。

相關問題