2016-03-03 79 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