带有扩展基本适配器的ListView未正确更新

时间:2015-04-30 18:07:35

标签: android listview baseadapter

我目前正在为Android上的ListView编写自定义BaseAdapter。当我第一次在ListView中插入项目时,列表适配器基本上工作正常,但是在中间插入新项目后,调用后会显示错误的项目

notifyDataSetChanged();

这是一个简化的例子(我把它剥离到只有必要的,如果我错过了任何信息,请说明评论):

public class FriendListAdapter extends BaseAdapter {

    private ArrayList<SingleFriend> data;
    private Activity activity = null;

    private static int needAccept = -1;
    private static int friend = -2;
    private static int waiting = -3;

    public FriendListAdapter(Activity a) {
        this.activity = a;
        data = new ArrayList<>();
    }

    public void AddFriend(SingleFriend newFriend, boolean silent) {

        int insertInto = 0;

        switch (newFriend.getFriendType()) {
            case TYPE_FRIEND_WAIT_FOR_YOUR_ACCEPT:
               insertInto = needAccept;
                break;
            case TYPE_FRIEND_WAIT_FOR_HIS_ACCEPT:
                insertInto = waiting;
                break;

            case TYPE_FRIEND_ACCEPTED:
                insertInto = friend;
                break;
        }

        if (insertInto < 0) {
            boolean found = false;
            boolean inserted = false;
            int index = 0;

            do {
                if (data.get(index).getFriendID() == insertInto) {
                    found = true;
                } else if (found) {
                    if (data.get(index).getFriendID() < 0) {
                        data.add(index, newFriend);
                        inserted = true;
                    } else {
                        if (newFriend.getFriendName().compareToIgnoreCase(data.get(index).getFriendName()) < 0) {
                            data.add(index, newFriend);
                            inserted = true;
                        }
                    }
                }
                if (!inserted && index == data.size() - 1) {
                    data.add(newFriend);
                    inserted = true;
                }
                ++index;
            } while (index < data.size() && !inserted);
        }
        if (!silent) {
            notifyDataSetChanged();
        }
    }

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

        View vi = convertView;
        if (vi == null) {
            LayoutInflater inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            SingleFriend friend = (SingleFriend)getItem(position);
            if (friend != null) {
                switch (friend.getFriendType()) {
                    case TYPE_SEPARATOR:
                        vi = inflater.inflate(R.layout.friendlist_topic, null);
                        vi.setTag(friend);
                        ((TextView)vi.findViewById(R.id.friendTopic)).setText(friend.getFriendName());
                        break;
                    case TYPE_FRIEND_ACCEPTED:
                    case TYPE_FRIEND_WAIT_FOR_HIS_ACCEPT:
                    case TYPE_FRIEND_WAIT_FOR_YOUR_ACCEPT:
                        // TODO: Community rating!
                        vi = inflater.inflate(R.layout.friendlist_item, null);
                        vi.setTag(friend);
                        ((TextView)vi.findViewById(R.id.friendName)).setText(friend.getFriendName());
                        break;
                    default:
                        break;
                }
            }
        }
        return vi;
    }
}

在FriendList中插入好友后,为什么显示错误的数据?我错过了什么吗?即使invalidate()也没有显示正确的东西(我知道,invalidate是一个糟糕的选择,我只是为测试目的而做了一次)。提前谢谢!

1 个答案:

答案 0 :(得分:1)

有太多问题,但我认为你要解决的问题是由这种情况检查造成的(或主要是由此引起的):

if (vi == null) {...
convertView方法中的

getView并非始终为null,而是在您满足上述检查时为该行的视图充气。我认为在您向上和向下滚动后,内容将不再正确关联项目。

我注意到的其他问题是,

每次修改适配器所耦合的列表时,都应该调用

notifyDataSetChanged。如果你想隐藏一些元素,那么你应该保留两个列表。适配器的一个纯粹用于显示。

我认为您希望根据ID的可用性将项目插入到列表中。如果是这种情况,那么比循环寻找ID的列表更好的方法是使用像HashMap<id, SingleFriend>这样的地图,get(id)可以随机访问。

您应该首先了解getView的工作原理并正确使用View Holder pattern