可过滤的 StickyListHeadersAdapter,notifyDataSetChanged 不工作

Filterable StickyListHeadersAdapter, notifyDataSetChanged not working

我已经在这个问题上停留了几个小时,我的想法是在 EditText 的帮助下创建一个可过滤的列表。为此,我使用带有可过滤 StickyListHeadersAdapter 的 StickyListHeadersListView。这是我当前的代码:

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 例如 Filter class returns我过滤了 2 个项目,然后将这个包含 2 个项目的列表传递给 notifyFilterDataSetChanged 函数,以便粘性列表仅显示 2 个项目。在这一点上它失败了,整个列表保持不变。我可能在这一点上失踪了,我一直在阅读所有好的建议,但都是徒劳的。有什么想法吗?

首先,您的 getItemId 实现有误。如果你使用 hasStableIds(true) 你不应该依赖位置。试着让它像

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

我想你的用户 class 中有某种 ID,是吗?

其次,您是否在UI 线程中调用publishResults?尝试让它运行 runOnUiThread() 或 listView.post() 来检查是否一切正常。

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