2016-03-03 84 views
0

我正在創建一個包含圖片,視頻,pdf等文件目錄的應用程序。我目前正在爲圖片顯示縮略圖。我使用RecyclerView和ViewHolder來顯示每個代表照片項目的列表項目。然後我使用AsyncTask一次下載一個Bitmaps,並將它們存儲在一個Hashmap中。除非我快速向下滾動大量照片,否則一切正常。列表底部隨機項目的佔位符圖像被替換爲已經加載到列表頂部的縮略圖。當後臺線程到達底部的圖像時,正確的圖像會替換錯誤的圖像。所有的縮略圖加載後,一切都按預期工作。使用AsyncTask bug將位圖縮略圖加載到RecyclerView中

以下是AsyncTask的代碼。我認爲這個問題與我傳遞給構造函數的位置整數有關。位置變量表示適配器中的位置。也許有一種方法可以確保圖像正在加載onPreExecute()中的佔位符圖像嗎?

/** 
* AsyncTask to download the thumbnails in the RecyclerView list. 
*/ 

private class CreateThumbnail extends AsyncTask<Void, Void, android.graphics.Bitmap> { 

    // ****** 
    // FIELDS 
    // ****** 

    private ImageView mPreviewInstance; 
    private File mFile; 
    private RelativeLayout.LayoutParams lp; 
    private FileHolder mFileHolder; 
    private int mPosition; 
    private UUID mId; 
    private FolderFile mFolderFile; 

    // *********** 
    // Constructor 
    // *********** 

    /** 
    * @param holder - ViewHolder passed for the list item. 
    * @param position - position in the Adapter. 
    * @param id - id for list item stored in database. 
    */ 

    private CreateThumbnail(FileHolder holder, int position, UUID id) { 
     mPosition = position; 
     mFileHolder = holder; 
     mPreviewInstance = mFileHolder.mImagePreview; 
     mId = id; 
     mFolderFile = FolderFileLab.get(getContext()).getFolderFile(mId); 
    } 

    // **************** 
    // OVERRIDE METHODS 
    // **************** 

    @Override 
    protected void onPreExecute() { 

    } 

    @Override 
    protected Bitmap doInBackground(Void... params) { 

     FolderFileLab lab = FolderFileLab.get(getContext()); 

     if (!lab.getCurrentMap().containsKey(mId)) { 
      mFile = lab.getPhotoFile(mFolderFile); 

      // Create Bitmap (Biggest use of memory and reason this background thread exists) 
      Bitmap bitmap = PictureUtils.getScaledBitmap(
        mFile.getPath(), getActivity()); 

      // Scales Bitmap down for thumbnail. 
      Bitmap scaledBitmap; 
      if (bitmap.getWidth() >= bitmap.getHeight()) { 
       scaledBitmap = Bitmap.createBitmap(bitmap, bitmap.getWidth()/2 
           - bitmap.getHeight()/2, 
         0, bitmap.getHeight(), bitmap.getHeight()); 
      } else { 
       scaledBitmap = Bitmap.createBitmap(bitmap, 0, bitmap.getHeight()/2 
           - bitmap.getWidth()/2, 
         bitmap.getWidth(), bitmap.getWidth()); 
      } 

      // Cache bitmap 
      HashMap<UUID, Bitmap> map = lab.getCurrentMap(); 
      map.put(mId, scaledBitmap); 
      lab.updateMap(map); 

      return scaledBitmap; 
     } else { 
      // If Hashmap already contains the id get the Bitmap. 
      return lab.getCurrentMap().get(mId); 
     } 
    } 

    @Override 
    protected void onPostExecute(Bitmap bitmap) { 

     // Checks to see if the bitmap is still displayed in the list. If not nothing happens. 
     // If it is then it displays the image. 
     if (mPreviewInstance.getVisibility() == View.VISIBLE && mFileHolder.getPosition() 
       == mPosition && bitmap != null) { 

      // Formatting for thumbnail 
      lp = new RelativeLayout.LayoutParams(
        RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout 
        .LayoutParams.WRAP_CONTENT); 
      lp.setMargins(7, 7, 7, 0); 

      // Displaying thumbnail on UI thread. 
      mPreviewInstance.setLayoutParams(lp); 
      mPreviewInstance.setBackground(null); 
      mPreviewInstance.setImageBitmap(bitmap); 
     } 
    } 

} 

這裏是一些相關的適配器代碼,其中AsyncTask啓動。

@Override 
    public void onBindViewHolder(FileHolder holder, int position) { 
     FolderFile file = mFiles.get(position); 
     holder.bindFile(file); 

     if (file.isPhoto()) { 
      createThumbnail = new CreateThumbnail(holder, position,file.getId()); 
      createThumbnail.execute(); 
     } 
    } 
+0

它的東西與您的適配器,顯示,看起來像 – tyczj

+0

你是對的,它在適配器。 –

回答

1

想通了! 我添加了代碼,在每次綁定後將照片更改爲佔位符圖像。這是我在適配器中更改的內容。

@Override 
    public void onBindViewHolder(FileHolder holder, int position) { 
     FolderFile file = mFiles.get(position); 
     holder.bindFile(file); 

     if (file.isPhoto()) { 
      Drawable placeholder = getResources().getDrawable(R.mipmap.picture_blu); 
      holder.mImagePreview.setBackground(placeholder); 
      holder.mImagePreview.setImageBitmap(null); 


      createThumbnail = new CreateThumbnail(holder, position, file.getId()); 
      createThumbnail.execute(); 
     } 
    } 
0

您的視圖已被回收,因此在異步任務完成時,imageView已被重用併爲其指定了一個新圖像。

你可以做的是給imageView分配一個標籤,它是你要加載到它的文件的文件名。您在異步任務中跟蹤相同的文件名。然後在你的AsyncTask中,在onPostExecute中,檢查imageView具有的標記是否與剛加載的文件名相同。如果是,則繼續並將位圖設置爲imageView。如果不是,那麼該視圖已被回收,您只需刪除剛剛創建的位圖;另一個異步任務將加載正確的位圖。

+0

我現在就試試這個。 –

+0

我根據照片名稱/ ID爲每個ImageView設置了一個標籤。然後,我將該標籤與AsyncTask中當前項目的名稱進行了比較。然後,我將佔位符圖像設置爲應該顯示的圖像。不過,我仍然得到同樣的錯誤。 –

+0

你能發佈你的更新代碼嗎? – Francesc