我正在创建一个应用程序,其文件目录包含图片,视频,pdf等。我目前正在处理显示图片的缩略图。我正在使用RecyclerView和ViewHolder来显示每个代表照片项目的列表项。然后我使用AsyncTask一次下载一个Bitmaps并将它们存储在Hashmap中。一切正常,除非我很快向下滚动一大堆照片。列表底部随机项的占位符图像将替换为已在列表顶部加载的缩略图。当背景线程到达底部的图像时,正确的图像将替换错误的图像。加载完所有缩略图后,一切都按预期工作。
这是AsyncTask的代码。我认为问题与我传递给构造函数的位置整数有关。 position变量表示适配器中的位置。也许有办法确保图像正在加载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 :(得分: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();
}
}
答案 1 :(得分:0)
您的视图已被回收,因此在异步任务完成时,imageView已被重复使用,并为其分配了新图像。
您可以做的是为imageView分配一个标记,该标记是您尝试加载到其中的文件的文件名。您可以在异步任务中跟踪相同的文件名。然后在您的AsyncTask中,在onPostExecute中,检查imageView具有的标记是否与您刚刚加载的文件名相同。如果是,则继续将位图设置为imageView。如果不是,则视图已被回收,您只需删除刚刚创建的位图;另一个异步任务将加载正确的位图。