我有一个自定义适配器,它扩展了ArrayAdapter,并实现了视图持有者模式来显示来自Web服务的数据(文本+图像)。
为了懒加载图像,我使用Android开发人员网站上的高级培训中的异步任务模式,
我还使用磁盘+RAM位图缓存。
当需要检索其他数据时,我添加一个页脚视图,单击该视图从Web服务中检索其他数据并将其添加到适配器中。
问题是当添加新数据时,一些可见的图像会改变,然后立即改回去,这会导致奇怪的闪烁。
除此之外,一切都正常工作,滚动很平滑。
就我所知,当添加新数据时,可见视图被刷新时会发生这些图像更改。
有没有办法绕过这种不必要的行为?
这是执行下载和管理异步任务的类。
为了懒加载图像,我使用Android开发人员网站上的高级培训中的异步任务模式,
我还使用磁盘+RAM位图缓存。
当需要检索其他数据时,我添加一个页脚视图,单击该视图从Web服务中检索其他数据并将其添加到适配器中。
问题是当添加新数据时,一些可见的图像会改变,然后立即改回去,这会导致奇怪的闪烁。
除此之外,一切都正常工作,滚动很平滑。
就我所知,当添加新数据时,可见视图被刷新时会发生这些图像更改。
有没有办法绕过这种不必要的行为?
这是执行下载和管理异步任务的类。
public class ImageDownloader {
private ImageCache mCache;
private int reqWidth;
private int reqHeight;
public void download(String url, ImageView imageView, ImageCache imageCache, int reqHeight, int reqWidth) {
mCache = imageCache;
this.reqHeight = reqHeight;
this.reqWidth = reqWidth;
if (cancelPotentialDownload(url, imageView)) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
task.execute(url);
}
}
private class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
private String url;
private WeakReference<ImageView> imageViewReference;
public BitmapDownloaderTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
protected Bitmap doInBackground(String... strings) {
Bitmap bitmap = null;
try {
bitmap = mCache.getBitmapFromURL(strings[0], reqWidth, reqHeight);
} catch (IOException e) {
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) bitmap = null;
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
private static class DownloadedDrawable extends ColorDrawable {
private WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;
public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
}
public BitmapDownloaderTask getBitmapDownloaderTask() {
return bitmapDownloaderTaskReference.get();
}
}
private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof DownloadedDrawable) {
DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
return downloadedDrawable.getBitmapDownloaderTask();
}
}
return null;
}
private static boolean cancelPotentialDownload(String url, ImageView imageView) {
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
if (bitmapDownloaderTask != null) {
String bitmapUrl = bitmapDownloaderTask.url;
if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
bitmapDownloaderTask.cancel(true);
} else {
return false;
}
}
return true;
}
这是适配器:
私有类PlaceAdapter继承ArrayAdapter { final int viewResourceId;
public PlaceAdapter(Context context, int textViewResourceId, List<PlaceModel> objects) {
super(context, textViewResourceId, objects);
viewResourceId = textViewResourceId;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
LayoutInflater inflater = getLayoutInflater();
convertView = inflater.inflate(viewResourceId, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
PlaceModel place = getItem(position);
holder.name.setText(place.getName());
holder.address.setText(place.getVicinity());
holder.position = position;
if (place.getIcon() != null) {
String url = mImageViewUrls.get(holder.image);
if (url == null || (url != null && !url.equals(place.getIcon()))) {
mDownloader.download(place.getIcon(), holder.image, mCache, 100, 100);
mImageViewUrls.put(holder.image, place.getIcon());
}
} else {
holder.image.setImageBitmap(null);
mImageViewUrls.remove(holder.image);
}
return convertView;
}
}
private class ViewHolder {
public final ImageView image;
public final TextView name;
public final TextView address;
public int position;
public ViewHolder(View row) {
image = (ImageView) row.findViewById(R.id.placeRow_imageView);
name = (TextView) row.findViewById(R.id.placeRow_placeName);
address = (TextView) row.findViewById(R.id.placeRow_placeAddress);
}
}
mImageViewUrls
是一个WeakHashMap<ImageView, String>
,它将ImageView
和url映射在一起,以便通过检查ImageView
是否已经显示所需的图像来减少冗余的异步任务调用。如果没有这个实现,在数据更改时所有可见图像都会闪烁。有了这个实现,只会发生在某些图像上。
编辑:我试图消除此问题的可能原因,首先我尝试完全绕过缓存实现并从网络下载每个位图,然后我尝试使用CommonsWare的Endless adapter包装我的适配器,并且两者都得到了相同的结果... 这只剩下ImageDownloader类和我的适配器作为可能的原因... 我完全迷失了。