基于BaseAdapter的ListView筛选失效求助:AppsAdapter调用filter无效果
解决ListView Adapter筛选无效果的问题
我看你现在遇到的是ListView调用filter()后没生效的问题,大概率是Filter的实现环节出了疏漏——毕竟BaseAdapter结合Filterable的时候,有几个关键细节没做好的话,筛选功能就是摆设。我帮你把完整的Adapter实现补全,同时把核心要点讲清楚:
核心注意点
首先要明确:必须把原始数据集和当前显示的数据集分开存储。如果直接在同一个列表上做过滤,不仅没法恢复原始数据,还会导致筛选逻辑混乱。
完整的AppsAdapter实现
class AppsAdapter extends BaseAdapter implements Filterable { private Context mContext; // 原始数据集:初始化后就不再修改,作为筛选的数据源 private List<Pair<String, List<String>>> mOriginalAppsWithPermission; // 当前显示的数据集:筛选后更新这个列表 private List<Pair<String, List<String>>> mFilteredAppsWithPermission; private ArrayFilter mFilter; // 构造方法:传入原始数据,同时初始化显示列表 AppsAdapter(Context context, List<Pair<String, List<String>>> appsWithPermission) { mContext = context; // 注意:这里要做深拷贝,避免原始数据被意外修改 mOriginalAppsWithPermission = new ArrayList<>(appsWithPermission); mFilteredAppsWithPermission = new ArrayList<>(appsWithPermission); } @Override public int getCount() { // 返回当前显示列表的数量 return mFilteredAppsWithPermission.size(); } @Override public Object getItem(int position) { return mFilteredAppsWithPermission.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // 这里写你的item布局渲染逻辑,比如获取TextView展示应用名称等 // 示例: if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.item_app, parent, false); } TextView appNameTv = convertView.findViewById(R.id.tv_app_name); Pair<String, List<String>> item = mFilteredAppsWithPermission.get(position); appNameTv.setText(item.first); return convertView; } @Override public Filter getFilter() { if (mFilter == null) { mFilter = new ArrayFilter(); } return mFilter; } // 核心的Filter实现类 private class ArrayFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); // 如果筛选关键词为空,直接返回原始数据 if (constraint == null || constraint.length() == 0) { results.values = new ArrayList<>(mOriginalAppsWithPermission); results.count = mOriginalAppsWithPermission.size(); } else { String filterStr = constraint.toString().toLowerCase().trim(); List<Pair<String, List<String>>> filteredList = new ArrayList<>(); // 遍历原始数据,根据关键词筛选(这里以应用名称为例,你可以改成自己的筛选规则) for (Pair<String, List<String>> item : mOriginalAppsWithPermission) { if (item.first.toLowerCase().contains(filterStr)) { filteredList.add(item); } } results.values = filteredList; results.count = filteredList.size(); } return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { // 更新显示列表,并通知Adapter数据变化 mFilteredAppsWithPermission = (List<Pair<String, List<String>>>) results.values; notifyDataSetChanged(); } } }
关键细节解释
- 数据集分离:
mOriginalAppsWithPermission保存完整的原始数据,永远不修改;mFilteredAppsWithPermission是当前ListView显示的列表,筛选后更新它。 - Filter的两个核心方法:
performFiltering:在后台线程运行,不能操作UI,只能基于原始数据生成筛选后的列表,最后通过FilterResults返回结果。publishResults:在UI线程运行,把筛选结果赋值给显示列表,然后调用notifyDataSetChanged()触发ListView更新。
- 筛选规则自定义:我上面的示例是根据应用名称(
item.first)包含关键词来筛选,你可以根据自己的需求修改,比如筛选权限列表里包含某个权限的应用。
调用方式(MainActivity中)
你原来的调用逻辑是对的,只要Adapter实现正确,这样调用就会生效:
// 比如筛选名称包含"微信"的应用 appsAdapter.getFilter().filter("微信");
内容的提问来源于stack exchange,提问作者faby GT
相关产品推荐
相关产品推荐

