所以我测试了上面的案例,确实观点的引用被完全滥用了。 AsyncTask 将图像放到错误的视图中,一切都变得一团糟。
我通过从 ViewHolder 保存指向 AsyncTask 的指针解决了这个问题,然后在 onBindViewHolder 中我取消了之前执行的 AsyncTask 并禁用了视图的可见性,直到它被新的 AsyncTask 再次设置为可见。
代码将阐明我的意图:
package com.teamagam.dailyselfie;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
class PictureAdapter extends RecyclerView.Adapter<PictureAdapter.PictureViewHolder> {
private LayoutInflater mInflater;
private List<PictureInfo> mPictureInfoList;
PictureAdapter(Context context, List<PictureInfo> pictureInfoList) {
mInflater = LayoutInflater.from(context);
mPictureInfoList = pictureInfoList;
}
@Override
public PictureViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.layout_picture, parent, false);
return new PictureViewHolder(view);
}
@Override
public void onBindViewHolder(PictureViewHolder pictureViewHolder, int position) {
PictureInfo pictureInfo = mPictureInfoList.get(position);
pictureViewHolder.mTextView.setText(pictureInfo.fileName);
int imageSize = pictureViewHolder.mImageView
.getContext()
.getApplicationContext()
.getResources()
.getInteger(R.integer.activity_main_thumbnail_size);
if (null != pictureViewHolder.mLoadPictureTask) {
pictureViewHolder.mLoadPictureTask.cancel(true);
}
pictureViewHolder.mImageView.setVisibility(View.INVISIBLE);
pictureViewHolder.mLoadPictureTask = new LoadPictureTask(pictureViewHolder.mImageView, imageSize);
pictureViewHolder.mLoadPictureTask.execute(pictureInfo.path);
}
@Override
public int getItemCount() {
return mPictureInfoList.size();
}
class PictureViewHolder extends RecyclerView.ViewHolder {
ImageView mImageView;
TextView mTextView;
LoadPictureTask mLoadPictureTask;
PictureViewHolder(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.ivItemListImage);
mTextView = (TextView) itemView.findViewById(R.id.tvItemListImage);
}
}
}
当然还有 AsyncTask 的代码:
package com.teamagam.dailyselfie;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.AsyncTask;
import android.view.View;
import android.widget.ImageView;
import java.lang.ref.WeakReference;
class LoadPictureTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> mImageViewReference;
private final int mImageSize;
LoadPictureTask(ImageView imageView, int imageSize) {
// Use a WeakReference to ensure the ImageView can be garbage collected
mImageViewReference = new WeakReference<>(imageView);
mImageSize = imageSize;
}
@Override
protected Bitmap doInBackground(String... params) {
String path = params[0];
return decodeSampledBitmapFromFile(path, mImageSize, mImageSize);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (mImageViewReference.get() != null && bitmap != null) {
final ImageView imageView = mImageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
imageView.setVisibility(View.VISIBLE);
}
}
}
private static Bitmap decodeSampledBitmapFromFile(String path, int requiredWidth, int requiredHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateSampleSize(options, requiredWidth, requiredHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
private static int calculateSampleSize(Options options, int requiredWidth, int requiredHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int sampleSize = 1;
if (height > requiredHeight || width > requiredWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest sampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / sampleSize) >= requiredHeight
&& (halfWidth / sampleSize) >= requiredWidth) {
sampleSize *= 2;
}
}
return sampleSize;
}
}