适配器上的notifydataSetChanged将使用新项目进行更新,但不会更新现有项目

WIl*_*JBD 7 java android

我找不到与我的确切问题有关的具体内容,请继续阅读以了解这是什么.

我非常谨慎地确保在我的代码中的所有地方,我设置正确的只是在适配器上调用notifyDataSetChanged,我初始化itemList一次,并将其传递给适配器,并且不要重新初始化它.

它就像一个魅力,列表视图将自行更新,但仅适用于新项目.

对于现有项目,ListView将无法正确更新.

例如,如果我有一个列表视图显示一些自定义项目,我需要更新它,我这样做

public void updateList(List<item> newItems)
{
    if (adapter == null)
    {
        itemList.addAll(newItems);
        adapter = new SomeAdapter(layoutInflator, itemList);
        listView.setAdapter(adapter);
    } else
    {
        // lets find all the duplicates and do all the updating
        List<item> nonDuplicateItems = new ArrayList<item>();
        for (Item newItem : newItems)
        {
            boolean isDuplicate = false;
            for (Item oldItem : itemList)
            {
                // are these the same item?
                if (newItem.id == oldItem.id)
                {
                    isDuplicate = true;
                    // update the item
                    olditem.text1 = newItem.text1;
                    oldItem.text2 = newItem.text2;
                }
            }

            if (isDuplicate == false)
            {
                // add the new item
                nonDuplicateItems.add(newItem);
            }
        }

        // I have tried just adding these new ones to itemList, 
        // but that doesnt seem to make the listview update the
        // views for the old ones, so I thought thuis might help
        // by clearing, merging, and then adding back
        nonDuplicateItems.addAll(itemList);
        itemList.clear();
        itemList.addAll(nonDuplicateItems);

        // finally notify the adapter/listview
        adapter.notifyDataSetChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在listview将始终更新以显示新项目,但它不会更新现有项目的视图.

这是真正的踢球者告诉我这是一个问题的问题:如果我调用adapter.getItem(position);更新的预先存在的项目,返回的项目将显示更新的更改,(意味着text1和text2将保持其新值),即使它没有反映在listview中!

如果我打电话,listView.invalidateViews();那么列表视图将显示更新,但我有两个问题,有时它会闪烁,有时候,有时如果我调用它并且它在notifyDataSetChanged可以完成到列表视图之前运行,我得到一个"列表视图未通知数据更改"错误!

有人对这个有了解吗?

@Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        ViewHolder viewHolder;
        if (convertView == null)
        {
            convertView = layoutInflator.inflate(R.layout.item_comment, null);
                    // when the holder is created it will find the child views
                    // it will then call refreshHolder() on itself
            viewHolder = new ViewHolder(convertView, position);
            convertView.setTag(viewHolder);
        } else
        {
            viewHolder = ((ViewHolder) convertView.getTag());
            viewHolder.refreshHolder(position);
        }
        return convertView;
    }

public void refreshHolder(int position)
{
    this.position = position;
    tvText1.setText(getItem(position).text1);
    tvText2.setText(getItem(position).text2);
}
Run Code Online (Sandbox Code Playgroud)

我想知道我应该做的是在使用复制构造函数添加到列表之前重新实例化我的所有项目.也许在通知适配器时,如果item仍然是相同的引用,适配器将假定没有更改,因此不会重绘该视图?或者也许适配器仅在收到通知时为新项目绘制新视图?

要添加另一个细节,如果我向下滚动使更新的视图离开屏幕,然后返回到它,它会显示正确的信息,因为listview刷新/重新制作该视图.

我想我需要listview刷新所有当前的视图,这invalidateViews();可能是我必须要做的.

有谁知道更多关于这个?

编辑:这里要求的是一个适用于此问题的适配器.

public class ItemAdapter extends BaseAdapter
{

    private final static int VIEWTYPE_PIC = 1;
    private final static int VIEWTYPE_NOPIC = 0;

    public List<Item> items;
    LayoutInflater layoutInflator;
    ActivityMain activity;

    public ItemAdapter(List<Item> items, LayoutInflater layoutInflator, ActivityMain activity)
    {
        super();
        this.items = new ArrayList<Item>();
        updateItemList(items);
        this.layoutInflator = layoutInflator;
        this.activity = activity;
    }

    public void updateItemList(List<Item> updatedItems)
    {
        if (updatedItems != null && updatedItems.size() > 0)
        {
            // FIND ALL THE DUPLICATES AND UPDATE IF NESSICARY
            List<Item> nonDuplicateItems = new ArrayList<Item>();
            for (Item newItem : updatedItems)
            {
                boolean isDuplicate = false;
                for (Item oldItem : items)
                {
                    if (oldItem.getId().equals(newItem.getId()))
                    {
                        // IF IT IS A DUPLICATE, UPDATE THE EXISTING ONE
                        oldItem.update(newItem);
                        isDuplicate = true;
                        break;
                    }
                }
                // IF IT IS NOT A DUPLICATE, ADD IT TO THE NON-DUPLICATE LIST
                if (isDuplicate == false)
                {
                    nonDuplicateItems.add(newItem);
                }
            }

            // MERGE
            nonDuplicateItems.addAll(items);
            // SORT
            Collections.sort(nonDuplicateItems, new Item.ItemOrderComparator());
            // CLEAR
            this.items.clear();
            // ADD BACK IN
            this.items.addAll(nonDuplicateItems);
            // REFRESH
            notifyDataSetChanged();
        }
    }

    public void removeItem(Item item)
    {
        items.remove(item);
        notifyDataSetChanged();
    }

    @Override
    public int getCount()
    {
        if (items == null)
            return 0;
        else
            return items.size();
    }

    @Override
    public Item getItem(int position)
    {
        if (items == null || position > getCount())
            return null;
        else
            return items.get(position);
    }

    @Override
    public long getItemId(int position)
    {
        return getItem(position).hashCode();
    }

    @Override
    public int getItemViewType(int position)
    {
        Item item = getItem(position);
        if (item.getPhotoURL() != null && URLUtil.isValidUrl(item.getPhotoURL()) == true)
        {
            return VIEWTYPE_PIC;
        }
        return VIEWTYPE_NOPIC;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        ItemHolder itemHolder;
        if (convertView == null)
        {
            if (getItemViewType(position) == VIEWTYPE_PIC)
            {
                convertView = layoutInflator.inflate(R.layout.item_pic, null);
            } else
            {
                convertView = layoutInflator.inflate(R.layout.item, null);
            }
                    // THIS CONSTRUCTOR ALSO CALLS REFRESH ON THE HOLDER FOR US
            itemHolder = new ItemHolder(convertView, position);
            convertView.setTag(itemHolder);
        } else
        {
            itemHolder = ((ItemHolder) convertView.getTag());
            itemHolder.refreshHolder(position);
        }
        return convertView;
    }

    @Override
    public int getViewTypeCount()
    {
        return 2;
    }

    @Override
    public boolean hasStableIds()
    {
        return false;
    }

    @Override
    public boolean isEmpty()
    {
        return (getCount() < 1);
    }

    @Override
    public boolean areAllItemsEnabled()
    {
        return true;
    }

    @Override
    public boolean isEnabled(int position)
    {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

好的,我现在试过这个

    @Override
    public boolean hasStableIds()
    {
        return true;
    }

    @Override
    public long getItemId(int position)
    {
        return getItem(position).hashCode();
    }
Run Code Online (Sandbox Code Playgroud)

还有这个

    @Override
    public boolean hasStableIds()
    {
        return false;
    }

    @Override
    public long getItemId(int position)
    {
        return getItem(position).hashCode();
    }
Run Code Online (Sandbox Code Playgroud)

我的hashcode是一个像apache这样的反射构建器(如果工作会导致基于值的哈希更改)

    @Override
    public int hashCode()
    {
        return HashCodeBuilder.reflectionHashCode(this);
    }
Run Code Online (Sandbox Code Playgroud)

它不起作用.据我所知,stableIds什么都不做.

编辑:

在稳定的Ids的任何组合中,这些都不起作用.再次,和往常一样,您必须在屏幕外滚动视图然后再打开以便更新它.

listview.refreshDrawableState();
listview.requestLayout();
listview.invalidateViews();
Run Code Online (Sandbox Code Playgroud)

kup*_*sef 7

这里有一个类似的问题,可能有一个解决方案:

ListView没有刷新已经可见的项目