我有一个扩展 ArrayAdapter 的自定义适配器,它实现了视图持有者模式以显示来自 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>在 an 和 url 之间映射的ImageView一个,因此可以通过检查是否ImageView已经显示所需的图像来减少冗余的异步任务调用。如果没有这个实现,数据变化时所有可见图像都会发生闪烁。有了这个,它只发生在一些图像上。
编辑:我试图消除这个问题的可能原因,首先我试图完全绕过缓存实现并从网络下载每个位图,然后我尝试用 CommonsWare 的 Endless 适配器包装我的适配器,我得到了相同的结果.. 所以这仅留下 ImageDownloader 类和我的适配器作为可能的原因。我对此完全迷失了。