可过滤的StickyListHeadersAdapter,notifyDataSetChanged无法正常工作

时间:2016-01-06 16:13:34

标签: android listview android-listview

我已经坚持了几个小时,我的想法是在EditText的帮助下有一个可过滤的列表。为此,我使用StickyListHeadersListView和可过滤的StickyListHeadersAdapter。这是我目前的代码:

public class PersonaFilterAdapter extends BaseAdapter implements StickyListHeadersAdapter, Filterable {

private int mResource;
private List<User> mUserList = new ArrayList<>();
private Set<User> mUserHashSet;

/** Filter parameters **/
private ArrayList<User> mFilteredObjects = new ArrayList<>();
private Filter mFilter;

public PersonaFilterAdapter(int resource, List<User> objects, Set<User> userHashSet) {
    this.mResource = resource;
    this.mUserList.addAll(objects);
    this.mFilteredObjects.addAll(objects);
    this.mUserHashSet = userHashSet;
}

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

    if (convertView == null) {
        convertView = LayoutInflater.from(parent.getContext()).inflate(mResource, parent, false);
        holder = new ViewHolder();
        holder.avatar = (SimpleDraweeView) convertView.findViewById(R.id.userAvatar);
        holder.name = (TextView) convertView.findViewById(R.id.userName);
        holder.position = (TextView) convertView.findViewById(R.id.userPosition);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    User user = getItem(position);

    int size = 100;
    String imgString = SlingCloudinary.getInstance().getAvatar(user, size, size);
    Uri uri = Uri.parse(imgString);
    holder.avatar.setImageURI(uri);
    holder.name.setText(String.format("%s %s", user.getName(), user.getLastname()));
    holder.position.setText(user.getDescription());

    if (mUserHashSet != null) {
        ListView listView = (ListView) parent;
        if (mUserHashSet.contains(user)) {
            listView.setItemChecked(position, true);
        } else {
            listView.setItemChecked(position, false);
        }
    }
    return convertView;
}

public void updateUsersList(List<User> userList) {
    mUserList.clear();
    mUserList.addAll(userList);
    mFilteredObjects.clear();
    mFilteredObjects.addAll(mUserList);
    this.notifyDataSetChanged();
}

public void notifyFilterDataSetChanged(List<User> userList) {
    mFilteredObjects.clear();
    mFilteredObjects.addAll(userList);
    notifyDataSetChanged();
}

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

@Override
public User getItem(int position) {
    return mFilteredObjects.get(position);
}

@Override
public int getCount() {
    return mFilteredObjects.size();
}

@Override
public Filter getFilter() {
    if (mFilter == null) {
        mFilter = new AppFilter();
    }
    return mFilter;
}

class ViewHolder {
    SimpleDraweeView avatar;
    TextView name;
    TextView position;
}

class HeaderViewHolder {
    TextView text;
}

@Override
public View getHeaderView(int position, View convertView, ViewGroup parent) {
    HeaderViewHolder holder;

    if (convertView == null) {
        holder = new HeaderViewHolder();
        convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.header_section_persona, parent, false);
        holder.text = (TextView) convertView.findViewById(R.id.personaSectionText);
        convertView.setTag(holder);
    } else {
        holder = (HeaderViewHolder) convertView.getTag();
    }

    // set header text as first char in name
    CharSequence headerChar = getItem(position).getName().subSequence(0, 1);
    holder.text.setText(headerChar);

    return convertView;
}

@Override
public long getHeaderId(int position) {
    return getItem(position).getName().subSequence(0,1).charAt(0);
}

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

private class AppFilter extends Filter {

    @Override
    protected FilterResults performFiltering(CharSequence chars) {
        FilterResults result = new FilterResults();
        if (chars != null && chars.length() > 0) {
            String mask = chars.toString();
            ArrayList<User> userList = new ArrayList<>();

            for (User user : mUserList) {
                if (keepObject(user, mask)) {
                    userList.add(user);
                }
            }
            result.count = userList.size();
            result.values = userList;
        } else {
            // add all objects
            result.values = mUserList;
            result.count = mUserList.size();
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        if (results.count > 0) {
            notifyFilterDataSetChanged((List<User>) results.values);
        } else {
            notifyDataSetInvalidated();
        }
    }
}

private boolean keepObject(User user, String mask) {
    mask = mask.toLowerCase();
    return user.getName().toLowerCase().startsWith(mask);
}
}

现在一切都显示得很好我打电话给 updateUsersList 列表函数调用 notifyDataSetChanged 并且它工作正常,我可以看到所有列表中的部分。

然后在使用EditText时,输入字母 B ,例如过滤器类返回2个过滤的项目,然后我将这2个项目的列表传递给< em> notifyFilterDataSetChanged 函数,以便粘性列表仅显示2个项目。此时它失败了,整个列表保持不变。我可能在这一点上失踪了,我一直在阅读所有好的建议但是徒劳无功。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

首先,你有一个错误的getItemId实现。如果你使用hasStableIds(true),你不应该依赖于位置。尝试使它像

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

我想你的User类中有某种id,不是吗?

其次,你在UI线程中调用publishResults吗?尝试使其运行runOnUhThread()或listView.post()来检查一切是否正确。

第三,你有几个适配器初始化?检查您是否将事件传递给正确的事件(绑定到列表视图的事件)。