2016-09-06 2 views
1

나는 RecyclerView.Adapter<RecyclerView.ViewHolder>을 확장하고 Filterable을 구현하는 adapter을 가지고 있습니다.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

버튼이 어댑터 를 정의 할 때 반환 하나 개의 모델이 메소드는 오버라이드 (override) 할 필요가이 메소드를 클릭하면 이것은 어댑터에서 필터링 할 수있는 최선의 대체 솔루션입니다. –

답변

1

사전 필터Person 항목을 입력 할 수 있습니다.

모든 단일 문자 제약 조건에 대해 Map 개의 목록 (실제로는 Set 초)을 만들고, 여러 개의 문자 제약 조건도 만들 수 있습니다.

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에 코드를 작성하지 않았으므로 몇 가지 문제가 있으면 놀라지 마십시오. 대부분 저는 방금 필터링을 시작하기 전에 항목을 작은 버킷에 배포하기위한 아이디어를 전달하고자했습니다. 그것이 어떻게 작동하는지 알려주십시오. –

관련 문제