列表底部的重复/左侧列表视图项

时间:2015-02-18 00:07:17

标签: java android listview duplicates adapter

我正在使用带有自定义适配器的ExpandableListView,该适配器显示具有在线状态的联系人列表。如果他们离线,那么我从列表中删除联系人。反之亦然,如果他们在线,那么我将他们添加到列表中。每次添加或删除联系人时,我都会notifyDataSetChanged()。随着时间的推移,我看到的是一些列表视图在列表底部重复。当我展开并折叠这些重复联系人的组时,它们就会消失。它看起来像是已经删除了这些重复的视图,但它们仍然存在并且视图被回收。发生了什么事?

通过广播改变在场状态。联系人的扩展名#是意图的附加内容。

private class PresenceReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equalsIgnoreCase(SIGNAL_ROSTER_CHANGE)) {
            int extension = intent.getIntExtra("EXTRA_EXTENSION", -1);
            if (extension != -1) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Contact contact = findContactByExtension(Integer.toString(extension));
                        if (contact != null) {
                            int presence = getPresenceForExtension(contact.getExtension());
                            if (presence == STATUS_UNKNOWN || presence == STATUS_INVISIBLE || presence == STATUS_OFFLINE) {
                                removeFromList(contact);
                            } else {
                                addToList(contact);
                            }
                        }
                    }
                });
            }
        }
    }
}

删除逻辑:遍历列表并删除与联系人匹配的所有实例。从列表中删除联系人时,请检查列表是否为空。如果列表为空,则删除组和列表。这是删除代码:

private void removeFromList(Contact contact) {
    if (listAdapter != null) {
        // Get adapter's child items
        List<List<Contact>> adapterListOfLists = listAdapter.getContactLists();     // Child items
        Iterator<List<Contact>> listIterator = adapterListOfLists.iterator();       

        int groupIndex = 0;
        // Iterate through list to find instances of the contact
        while (listIterator.hasNext()) {
            List<Contact> listPart = listIterator.next();
            Iterator<Contact> contactIterator = listPart.iterator();

            while (contactIterator.hasNext()) {
                Contact compareContact = contactIterator.next();
                if (contact.equals(compareContact)) {
                    contactIterator.remove();
                    listAdapter.notifyDataSetChanged();
                }
            }

            // Check if list is empty after removal
            if (listPart.size() == 0) {
                // Remove the list's group
                List<String> adapterGroups = listAdapter.getContactGroup();
                adapterGroups.remove(groupIndex);
                // Remove the empty list
                listIterator.remove();
                listAdapter.notifyDataSetChanged();
            }
            groupIndex++;
        }
    }
}

联系人按名字排序,并按名称第一个字符的字母分组。如果名称的第一个字符不是字符,则将其归类于组:“#”。

添加联系人的逻辑: 检查联系人的组是否存在。如果存在,则存在子数据,并且我们对插入联系人的位置进行二进制搜索。如果该组不存在,则子数据不存在。我进行二进制搜索以查找组所属的位置并创建它。然后在子数据的相应索引中,我创建一个新列表,将联系人添加到列表中,并将列表插入与其组对应的索引中。这是插入代码:

private void addToList(Contact contact) {
    String contactName;
    String indexKey = "#";

    if (contact.getFirstName().length() > 0) {
        contactName = contact.getFirstName();
    } else {
        contactName = contact.getLastName();
    }

    if (contactName.length() > 0 && Character.isLetter(contactName.charAt(0))) {
        indexKey = Character.toString(contactName.charAt(0));
    }

    insertContact(contact, indexKey);
}

private void insertContact(Contact contact, String group) {
    if (listAdapter != null) {
        List<List<Contact>> adapterListOfLists = listAdapter.getContactLists();
        List<String> adapterGroups = listAdapter.getContactGroup();

        String capitalizeFirstLetter = group.substring(0, 1).toUpperCase(Locale.getDefault());

        group = capitalizeFirstLetter;

        int groupIndex = adapterGroups.indexOf(group);

        if (groupIndex == -1) {
            int insertGroupTitleIndex = Collections.binarySearch(adapterGroups, group, new GroupTitleComparator());

            if (insertGroupTitleIndex < 0) {
                insertGroupTitleIndex = -insertGroupTitleIndex - 1;
            }

            adapterGroups.add(insertGroupTitleIndex, group);

            List<Contact> newList = new ArrayList<Contact>();
            newList.add(contact);
            adapterListOfLists.add(insertGroupTitleIndex, newList);
        } else {
            List<Contact> groupList = adapterListOfLists.get(groupIndex);
            int insertIndex = Collections.binarySearch(groupList, contact, new ContactComparator(sortType.SORT_BY_FIRST_NAME);

            if (insertIndex < 0) {
                insertIndex = -insertIndex - 1;
            }

            groupList.add(insertIndex, contact);
        }
        listAdapter.notifyDataSetChanged();
    }
}

这是适配器的getGroupView():

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    GroupViewHolder groupHolder;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.directory_alphabet_title, parent, false);

        groupHolder = new GroupViewHolder();
        groupHolder.title = (TextView) convertView.findViewById(R.id.group_title);
        groupHolder.childrenCount = (TextView) convertView.findViewById(R.id.group_title_child_count);

        convertView.setTag(groupHolder);
    } else {
        groupHolder = (GroupViewHolder) convertView.getTag();
    }

    if (getChildrenCount(groupPosition) > 0) {
        groupHolder.title.setVisibility(View.VISIBLE);
        groupHolder.childrenCount.setVisibility(View.VISIBLE);
        groupHolder.title.setText((String) getGroup(groupPosition));
        groupHolder.childrenCount.setText(Integer.toString(getChildrenCount(groupPosition)));
    } else { // If contactGroup has no contactLists then hide it
        groupHolder.title.setVisibility(View.GONE);
        groupHolder.childrenCount.setVisibility(View.GONE);
    }

    return convertView;
}

getChildView():

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
    ChildViewHolder childHolder;

if (convertView == null) {
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    convertView = inflater.inflate(R.layout.list_item_contact, parent, false);

    childHolder = new ChildViewHolder();

    childHolder.contactName = (TextView) convertView.findViewById(R.id.contact_name);
    childHolder.statusIcon = (ImageView) convertView.findViewById(R.id.status_icon);

    convertView.setTag(childHolder);
} else {
    childHolder = (ChildViewHolder) convertView.getTag();
}

final Contact contact = (Contact) getChild(groupPosition, childPosition);

if (contact.getContactType().equals("corporate")) {
    int presence = 0;

    presence = getPresenceForExtension(contact.getExtension());

    switch (presence) {
    case STATUS_ONLINE:
        childHolder.statusIcon.setImageResource(R.drawable.icon_status_available);
        break;
    case STATUS_BUSY:
        childHolder.statusIcon.setImageResource(R.drawable.icon_status_busy);
        break;
    case STATUS_DND:
        childHolder.statusIcon.setImageResource(R.drawable.icon_status_dnd);
        break;
    case INCALL:
        childHolder.statusIcon.setImageResource(R.drawable.icon_status_oncall);
        break;
    case AWAY:
        childHolder.statusIcon.setImageResource(R.drawable.icon_status_away);
        break;
    case STATUS_UNKNOWN:
    case STATUS_OFFLINE:
    case STATUS_INVISIBLE:
    default:
        childHolder.statusIcon.setImageResource(R.drawable.icon_status_invisible);
        break;
    }
}

childHolder.contactName.setText(contact.getName());

childHolder.contactName.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // Open detail page of this contact
    }
});

childHolder.callButton.setFocusable(false);
childHolder.chatButton.setFocusable(false);
childHolder.favoriteButton.setFocusable(false);
return convertView;

}

适配器的组和子数据,位于适配器类内:

private List<List<Contact>> contactLists;
private List<String> contactGroup;

public List<List<Contact>> getContactLists() {
    return contactLists;
}

public void setContactLists(List<List<Contact>> contactLists) {
    this.contactLists = contactLists;
}

public List<String> getContactGroup() {
    return contactGroup;
}

public void setContactGroup(List<String> contactGroup) {
    this.contactGroup = contactGroup;
}

更新:我找到的唯一选择是保存第一个可见项目的位置。然后使用修改后的列表创建一个新的适配器,将其设置为列表视图,然后移回到之前记录的第一个可见项目的位置。还有更好的方法吗?

0 个答案:

没有答案