【问题标题】:ImageViews in Android ListView are Showing Previously Loaded ImagesAndroid ListView 中的 ImageViews 正在显示以前加载的图像
【发布时间】:2014-12-09 23:14:56
【问题描述】:

我有一个安卓ListView,它使用AsyncTask 为每个ListViewItem 下载不同的图像。每张图片在第一次下载时都会添加到ArrayList<Bitmap>,之后每次都可以从ArrayList<Bitmap> 访问。

如果我慢慢滚动浏览ListView,每个图像都会按预期加载,但如果我开始更快地滚动,尚未下载其图像的可见ListViewItems 开始显示已经滚动的项目的图像离开屏幕顶部。

最终一切都同步了,图像通过onPostExecution 调用更新,但出了什么问题/如何防止以前项目中的图像出现在ListView 的下部项目中?

这是精简后的代码:

private ArrayList<Bitmap> bitmapArray = new ArrayList<Bitmap>(500); 


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

    View itemView;
        if (convertView == null) {
            itemView = getInflater().inflate(ITEM_LAYOUT, parent, false);
        } else {
            itemView = convertView;
        }

        final ImageView mImageView = (ImageView) itemView.findViewById(R.id.app_component_joblistitemview_logo);

        if (bitmapArray.size()>position && bitmapArray.get(position)!=null) {
            // Item exists at bitmapArray[position], use it
            Log.i("JobListView","Setting Existing for Position:"+position);
            mImageView.setImageBitmap(bitmapArray.get(position));
        } else {
            // Have not downloaded this ListView[position] logo yet        
            bitmapArray.add(position,null); // add temporary null value until the image is downloaded
            mImageView.setImageBitmap(null);
            new DownloadImageTask().execute(logo.getLogoUUID(), mImageView, position);
        }

        return itemView;
    }


    // This AsyncTask downloads an image / logo from a specified URL and then updates the specified ImageView
    private class DownloadImageTask extends AsyncTask<Object, Void, Bitmap> {

        ImageView imageView;
        Integer listViewPosition;

        @Override
        protected Bitmap doInBackground(Object... params) {
            String urlString = "http://www.myimages.com/something/"+params[0].toString();

            this.imageView = (ImageView)params[1];
            this.listViewPosition = (Integer)params[2];

            try {
                URL url = new URL(urlString);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setDoInput(true);
                connection.connect();
                InputStream input = connection.getInputStream();
                Bitmap myBitmap = BitmapFactory.decodeStream(input);
                bitmapArray.set(listViewPosition,myBitmap);
                return myBitmap;

            } catch (Exception e) {
                // Log exception
            }
        }

        protected void onPostExecute(Bitmap result) {
            imageView.setImageBitmap(result);
        }
    }

【问题讨论】:

  • 写一个好的/工作的图像加载器并不是一件容易的事......最好使用已经写好的......你将面临的下一个问题是内存管理...... ArrayList 当然将导致OOE Sonner或更晚

标签: android listview android-asynctask android-imageview


【解决方案1】:
else {
        // other methods, then set tag and run task
        mImageView.setTag(logo.getLogoUUID());
        new DownloadImageTask().execute(logo.getLogoUUID(), mImageView, position);
    }

int uuid=-1;

protected Bitmap doInBackground(Object... params) {
        uuid=params[0];
        //other methods
}

protected void onPostExecute(Bitmap result) {
    //if tag exists check validity
    if(imageView.getTag()==null && imageView.getTag().equals(uuid))
        imageView.setImageBitmap(result);
}

假设您有 2 张图片 - 第一张 10px 正方形,第二张 FHD。当您的项目需要全高清位图下载器开始下载时,obvius。当您仍在滚动并且此项目被“滚动”时,它会出现在下方(或上方,取决于滚动方向)(作为回收/转换视图)。然后你正在设置下载 10px 位图,它的速度要快得多。设置了 10 px,但之前的 asynctask 下载 fhd 图片仍在运行,仍然保持对 imageView 的引用。因此,当下载 fhd 时,它将替换这 10 像素。对于解决方法,您可以设置任何识别参数,您的“uuid”可能非常适合此

listView 和适配器是如何工作的,您可以阅读 herehere - 检查方法 convertView 中的 convertView 是什么,您可能会使用 ViewHolder 模式

附言。由于清理,我在您的代码中看到了一些空指针?示例:

View itemView;
final ImageView mImageView = //itemView is just created, findViewById will throw NPE
    (ImageView) itemView.findViewById(R.id.app_component_joblistitemview_logo);

【讨论】:

  • 好的。我明白你在说什么。为什么它不跟踪每个AsyncTask 指的是哪个ListItem / ImageView?不是每个ListItem 都创建了自己独特的ImageView 对象吗?
  • 是的,它可能,但出于性能目的,您应该回收您的视图(使用 convertView nad ViewHolder 模式)。然后你必须像我说的那样下载。您已经清除了一些 getItemView 方法,我发现了例如空指针(见编辑),所以我真的不知道你是如何创建这个 ImageViews
  • ItemView 被定义,我更新了代码来显示这个。
  • 检查您的行 itemView = convertView; - 在此之后您将获得 ImageView。这个 ImageView 是从屏幕上消失的同一个对象(“滚动出去”),所以之前盯着的 AsyncTask 保持对这个的引用。 ListView 只创建了几个 listItem 视图来填充屏幕,当您滚动一个项目时消失并从另一侧显示为新项目 - 请阅读我的答案中链接的这两个链接
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多