安卓:将数据添加到ArrayAdapter时可见的ListView图像闪烁 [英] Android: visible ListView images flicker when adding data to ArrayAdapter

查看:227
本文介绍了安卓:将数据添加到ArrayAdapter时可见的ListView图像闪烁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有延伸ArrayAdapter自定义适配器,它实现了观点持有者模式向Web服务显示的数据(文字+图片)。

I have a custom adapter which extends ArrayAdapter, it implements the view holder patterns to show data (text + image) from a web service.

有关我用的是异步工作模式从Android的开发者网站上的先进的训练图像的延迟加载,

for lazy loading of the images I use the async tasks pattern from the advanced training in the Android's developers site,

我还使用磁盘+ RAM位图缓存。

I also use disk + ram bitmap cache.

当存在要被检索到的I添加页脚认为点击它从web服务检索附加数据,并把它添加到适配器附加数据

when there is additional data to be retrieved I add a footer view that clicking on it retrieves additional data from the web service and add it to the adapter.

的问题是,当这些新的数据被添加,一些可见图像被改变,并立即变回,这导致奇怪闪烁。

the problem is that when this new data is being added, some of the visible images are changing and immediately changing back, which result in a weird flickering.

高于一切其他工作正常的滚动顺畅。

other than that everything is working fine and the scrolling is smooth.

据我了解,当看到视图被刷新,当新数据添加这些图像的变化正在发生。

as far as I understand those image changes are happening when the visible views are being refreshed when new data is added.

是有办法绕过这个不必要的行为?

is there a way to bypass this unwanted behavior ?

这是该类做下载和管理异步任务

this is the class doing the downloading and managing the async tasks

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 {         最终诠释viewResourceId;

private class PlaceAdapter extends 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&LT; ImageView的,字符串&GT; 这之间的地图ImageView的和一个网址,让多余的异步任务调用,可以通过检查的ImageView 已经显示出所需要的图像缩小。没有这种实现,闪烁是发生在对数据变化的所有可见的图像。与此,它发生只对某些图像

mImageViewUrls is a WeakHashMap<ImageView, String> that maps between an ImageView and a url, so redundant async tasks invocations can be reduced by checking if the ImageView is already showing the required image. without this implementation, flickering is happening in all visible images on data change. with this, it happens only with some images.

编辑:我试图消除这个问题的可能原因,首先,我想完全绕过缓存实现,并从网络上下载的每个位图,然后我试图包装我的适配器CommonsWare的无尽适配器以及带我得到了相同的结果..所以只留下了ImageDownloader类和我的适配器,可能的原因......我彻底对这个失去了。

I tried to eliminate possible causes of this issue, first I tried to completely bypass the cache implementation and download each bitmap from the network, then I tried wrapping my adapter with CommonsWare's Endless adapter and with both I got the same result.. so this leaves only the ImageDownloader class and my adapter as possible causes.. I'm completely lost on this.

推荐答案

这样做的理由忽悠的是,在列表视图列表中的项目被重用。当再次使用时,在列表项目的imageviews保留其首先显示旧的图像引用。后来一次新的图像被下载,它开始显现。这将导致闪烁的行为。 为了避免这种闪烁问题,始终清除时,它是越来越重复使用ImageView的旧图像引用。

The reason for this flicker is that, in listview list items are reused. When re-used, the imageviews in the list item retains the old image reference which is displayed first. Later on once new image is downloaded, it starts to show. this causes the flickering behavior. To avoid this flickering issue, always clear the old image reference from the imageview when it is getting reused.

在你的情况下,增加的 holder.image.setImageBitmap(空); 之后的持有人=(ViewHolder)convertView.getTag();

In your case, add holder.image.setImageBitmap(null); after holder = (ViewHolder) convertView.getTag();

那么,你的getView()方法如下:

So, your getView() method will look like:

@覆盖 公共查看getView(最终诠释的立场,观点convertView,ViewGroup中父){

@Override public View getView(final int position, View convertView, ViewGroup parent) {

...

if (convertView == null) {
    LayoutInflater inflater = getLayoutInflater();
    convertView = inflater.inflate(viewResourceId, null);

    holder = new ViewHolder(convertView);
    convertView.setTag(holder);
} else {
    holder = (ViewHolder) convertView.getTag();
    holder.image.setImageBitmap(null)
}

...

return convertView;

}

这篇关于安卓:将数据添加到ArrayAdapter时可见的ListView图像闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆