查看回收原因视图多次更新

时间:2014-07-26 06:46:32

标签: android listview

我使用andorid布局来显示书籍对象,包括其名称,作者和封面图像。

然而,本书的信息可能并不完整,因此我可能需要异步加载书籍细节,一旦书籍有封面(book.icon字段),我也需要加载图像。

例如,我第一次拿到了一本带有namedetailLink属性的书,所以我需要加载detailLink的html文档,然后解析文档以填充author icondescription字段等

我使用volley库。

这是使用getView模式的适配器的viewholder

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.common_dynamic_book, null);

            viewHolder = new ViewHolder();
            viewHolder.bName = (TextView) convertView.findViewById(R.id.book_name);
            viewHolder.bAuthor = (TextView) convertView.findViewById(R.id.book_author);
            viewHolder.bDescriptoin = (TextView) convertView.findViewById(R.id.book_description);
            viewHolder.bImage = (ImageView) convertView.findViewById(R.id.book_image);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        Book bk = getItem(position);
        viewHolder.book = bk;

        setupViewHolder(viewHolder);

        if (bk.icon == null) {
            StringRequest request = new StringRequest(bk.detailLink, new Response.Listener<String>() {
                @Override
                public void onResponse(String content) {
                    new ParseTask().execute(content, finalViewHolder);
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError volleyError) {

                }
            });
            queue.add(request);
        }
        return convertView;
    }

    private void setupViewHolder(final ViewHolder viewHolder) {
        Book bk = viewHolder.book;
        viewHolder.bName.setText(bk.name);
        viewHolder.bAuthor.setText(bk.author);
        if (bk.description != null) {
//          viewHolder.bDescriptoin.setText(bk.description);
        }
        if (bk.icon != null && !bk.icon.equals("none")) {
            imageLoader.get(bk.icon, new ImageLoader.ImageListener() {
                @Override
                public void onResponse(ImageLoader.ImageContainer imageContainer, boolean b) {
                    viewHolder.bImage.setImageBitmap(imageContainer.getBitmap());
                }

                @Override
                public void onErrorResponse(VolleyError volleyError) {
                }
            });
        }
    }

    class ParseTask extends AsyncTask<Object, Void, ViewHolder> {
        @Override
        protected ViewHolder doInBackground(Object... objects) {
            String content = (String) objects[0];
            ViewHolder viewHolder = (ViewHolder) objects[1];

            parser.buildBook(content, viewHolder.book);  //parse the html document, and fill the book object with information
            return viewHolder;
        }

        @Override
        protected void onPostExecute(ViewHolder viewHolder) {
            setupViewHolder(viewHolder);
        }
    }

一切都很好,但我遇到了问题:

当我快速搜索列表视图时(就像一个轻松的手势),我会发现视图可能会被更新很多次。

例如,首先,适配器有10本书,其详细信息未加载。书名为Book1 Book2 .... Book10

然后backgournd进程将开始加载该书,一旦我从上到下推送listview,我会发现一个列表项将被多次更新。例如,它首先显示名称Book8(没有进一步的信息),然后更改为(Book4加载详细信息),然后可能是另一本带有加载信息的书, AND FINALLY 显示带有加载信息的Book8

这似乎是由视图回收引起的。我想知道是否有可能取消这个?


更新

我认为这是由视图回收引起的,例如,视图首先被绑定到Book4,后台加载任务开始,然后当我滚动listview时,android重用此视图来显示项目Book8,当Book4的请求到达,并且视图更新为Book4,然后Book8任务完成,视图再次更新。我认为这是问题,但我不知道如何解决它......

2 个答案:

答案 0 :(得分:0)

我强烈建议您使用Picasso library,因为它会为您自动缓存图像,并为大型图像数据集提供了很好的实现,这是您的情况!

他们的样本中也有一个类似于你应该实现的例子: SampleListDetailAdapter

希望它有所帮助!

答案 1 :(得分:0)

您需要使用ViewHolder传递网址。

private static class ViewHolder {
   // Your members

   String url;
}

getView方法:

getView(..) {

        Book bk = getItem(position);
        viewHolder.book = bk;

        // Do not recreate view if it is the same view
        if (bk.icon != null && viewHolder.url != null && viewHolder.url.equals(bk.detailLink))
           return convertView;

        viewHolder.url = bk.detailLink;
}

当你收到回复时:

if (bk.icon != null && !bk.icon.equals("none")) {
                imageLoader.get(bk.icon, new ImageLoader.ImageListener() {
                    @Override
                    public void onResponse(ImageLoader.ImageContainer imageContainer, boolean b) {

                        if (!imageContainer.getUrl().equals(viewHolder.url))
                            return;

                        viewHolder.bImage.setImageBitmap(imageContainer.getBitmap());
                    }

                    @Override
                    public void onErrorResponse(VolleyError volleyError) {
                    }
                });
            }