2016-09-06 94 views
1

我有一个adapter,它扩展了​​并实现了Filterable使用RecyclerView.Adapter过滤很多条目

getFilter()实现:

@Override 
    public Filter getFilter() { 
     return new Filter() { 
      @Override 
      protected void publishResults(CharSequence constraint, FilterResults results) { 
       mPersonListFiltered = (List<Person>) results.values; 
       notifyDataSetChanged(); 
      } 

      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 
       FilterResults results = new FilterResults(); 
       List<Person> filtered = new ArrayList<>(); 

       if (constraint == null || constraint.length() == 0) { 
        results.count = mPersonList.size(); 
        results.values = mPersonList; 
       } else { 
        String name, email, constr = Utils.removeDiacriticalMarks(constraint.toString()); 
        for (Person person : mPersonList) { 
         name = Utils.removeDiacriticalMarks(person.getName().toLowerCase()); 
         email = person.getEmail().toLowerCase(); 
         if (name.contains(constr) || email.contains(constr)) { 
          filtered.add(person); 
         } 
        } 
        results.count = filtered.size(); 
        results.values = filtered; 
       } 
       return results; 
      } 
     }; 
    } 

我想打字时过滤我的人名单。如果我的列表大小不超过1k,这可以正常工作,但如果我将它扩展到5k,10k等等,它开始变得迟缓。而且我明白为什么,对于每个我必须检查是否包含他们的姓名和电子邮件限制的人来说,这太可怕了。 但是我想知道在这种情况下,是否有很多条目,为达到相同结果,最好的实现或替代方案是什么,换句话说,本地巨大列表的快速过滤方法和“即时”打字。

谢谢。

+0

您可以在适配器上的方法创建,当按钮点击这个方法会返回一个模型,这种方法,当你定义适配器 必须覆盖这是适配器中可过滤的最佳替代解决方案 –

回答

1

您可以预过滤器您的Person条目。

您会为所有单字符约束创建一个Map列表(实际上为Set s),也可能是一些多字符约束。

Map<String, Set<Person>> mFilteredPersonMap = new HashMap<>(); 

当你的Person是清单的适配器,将它们添加到地图中的一组:

   for (Person person : mPersonList) { 
        String name = Utils.removeDiacriticalMarks(person.getName().toLowerCase()); 
        for (char c : name.toCharArray()) { 
         if (Character.isWhitespace(c)) continue; 
         // you may want to skip other chars i.e. symbols 
         Set<Person> set = mFilteredPersonMap.get(Character.toString(c)); 
         if (set == null) { 
          set = new HashSet<>(); 
          mFilteredPersonMap.put(Character.toString(c), set); 
         } 
         set.add(person); 
        } 
        // do the same thing for email 
       } 

我使用的每一个字母的名称,因为您在最初的代码中使用contains(constr) 。我喜欢搜索字边界后的字符(正则表达式"\\b(\\w)"),并将它们用作地图的关键字。

然后使用地图作为第一级过滤:

 @Override 
     protected FilterResults performFiltering(CharSequence constraint) { 
      FilterResults results = new FilterResults(); 
      List<Person> filtered = new ArrayList<>(); 

      if (constraint == null || constraint.length() == 0) { 
       results.count = mPersonList.size(); 
       results.values = mPersonList; 
      } else { 
       String name, email, constr = Utils.removeDiacriticalMarks(constraint.toString()); 
       String key = constr.substr(0, 1); 
       Set set = mFilteredPersonMap.get(key); 
       if (set != null) { 
        // now you are looping through a smaller collection 
        for (Person person : set) { 
         name = Utils.removeDiacriticalMarks(person.getName().toLowerCase()); 
         email = person.getEmail().toLowerCase(); 
         if (name.contains(constr) || email.contains(constr)) { 
          filtered.add(person); 
         } 
        } 
       } 
       results.count = filtered.size(); 
       results.values = filtered; 
      } 
      return results; 
     } 
+0

这种方法看起来非常有趣。明天我会试试看,谢谢你的回答;) – GuilhE

+0

我没有在IDE或任何其他地方编写代码,所以如果它有一些问题不要感到惊讶。大多数情况下,我只是想传达这个想法,只是在过滤开始之前将您的条目分发到较小的存储桶中。让我知道它是如何工作的。 –