Android Recycler view adapter filter with animation
Asked Answered
C

3

7

I am trying to optimize the filter method for RecyclerView Adapter in Android. The list is used as an ArrayList. I have seen this post but they are filtering from the original list every time.

Example: if there are 10 results for String 'a' then user type 'm' , 'am' results are subset of 'a' results(results.size()<=10).

I have three points to ask in this question,

  1. Can I optimize HashMap memory by using ArrayMap? Should I use comma separated positions in String instead of Integer objects array or any way to use int primitive array?
  2. I am not getting any animation in this result, how to get that? (I am using notifyItemInserted still no animation)
  3. How much data should be kept in Hashmap, till 2 characters or it should be according to result list size?
I would be glad to know if anything can be done better in this code other than these points.

In below code, mList is used in onBindViewHolder method. copyList always contains all data(no insertion or deletion is done on that).

class MyFilter extends Filter {


        /**
         * 1. check do we have search results available (check map has this key)
         * 2. if available, remove all rows and add only those which are value for that key (string)
         * 3. else check do we have any key available starting like this, s=har, already available -ha then it can be reused
         *
         * @param constraint
         */
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            //Here you have to implement filtering way
            final FilterResults results = new FilterResults();

            if (!mSearchMap.containsKey(constraint.toString())) {
                String supersetKey = getSupersetIfAvailable(mSearchMap, constraint.toString());
                if (supersetKey == null) {
                    List<Integer> foundPositions = doFullSearch(copyList, constraint.toString());
                    mSearchMap.put(constraint.toString(), foundPositions);
                } else {
                    List<Integer> foundPositions = filterFromSuperset(copyList, mSearchMap.get(supersetKey), constraint.toString());
                    mSearchMap.put(constraint.toString(), foundPositions);
                }
            }


            return results;
        }

        private String getSupersetIfAvailable(Map<String, List<Integer>> mSearchMap, String s) {
            Set<String> set = mSearchMap.keySet();
            List<String> list = new ArrayList<>(set);
            Collections.sort(list);
            Collections.reverse(list);
            for (String c : list) {
                if (s.startsWith(c)) {
                    return c;
                }
            }
            return null;
        }
        private List<Integer> filterFromSuperset(List<WeekWorkBean> list, List<Integer> supersetResults, String s) {
            List<Integer> results = new ArrayList<>();
            String lowerS = s.toLowerCase();
            for (int i = 0; i < supersetResults.size(); i++) {
                if (list.get(supersetResults.get(i)).getEmpName().toLowerCase().startsWith(lowerS)) {
                    results.add(supersetResults.get(i));
                }
            }
            return results;
        }

        private List<Integer> doFullSearch(List<WeekWorkBean> list, String s) {
            List<Integer> results = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getEmpName().toLowerCase().startsWith(s.toLowerCase())) {
                    results.add(i);
                }
            }
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            // here you can use result - (f.e. set in in adapter list)
            mList.clear();
            notifyDataSetChanged();
            List<Integer> res = mSearchMap.get(constraint.toString());
            int j = 0;
            for (Integer i : res) {
                mList.add(copyList.get(i));
                notifyItemInserted(j++);
            }
        }
    }
Chiapas answered 2/12, 2016 at 9:14 Comment(3)
check my answer, DiffUtils is what are you looking forAlmallah
and these 2 points, Can I optimize HashMap memory by using ArrayMap? Should I use comma separated positions in String instead of Integer objects array or any way to use int primitive array? How much data should be kept in Hashmap, till 2 characters or it should be according to result list size?Chiapas
@Almallah your answer is useful and i have given a upvote. but it is not answering complete questionChiapas
A
4

Check this out https://medium.com/@iammert/using-diffutil-in-android-recyclerview-bdca8e4fbb00#.ehc0gaijt

DiffUtils is what are you looking for. You can use it in Rx chain to move it out of mainThread for a large data. here is a example https://medium.com/@nullthemall/diffutil-is-a-must-797502bc1149#.yg35y9q9b

Almallah answered 2/12, 2016 at 9:20 Comment(0)
G
1

To give an answer for your 2nd point you can try this:

 notifyItemRangeChanged(pos, ItemList.size());
Gynarchy answered 9/12, 2016 at 7:46 Comment(0)
N
1
  1. HashMap is a Map, there are also TreeMap, LinkedHashMap and Hashtable. each of them has own features and interface is Map, not Collection. You can also use other data structures, like Treeset, HashSet, ArrayList, LinkedList and etc. These structures comes from Set and List interface, which extends to Collection interface. You can use each of them.

  2. If you insert any object to your collection, use notifyItemInserted(int position), if you delete any object use notifyItemRemoved(int position), if you update any object use notifyDataSetChanged(). Be careful about equality of your collection length and adapter view count.

  3. You can store parameter in maps how much you want. There is not any limitation. But you should choose best Collection for you, set, list or map.

Not answered 11/12, 2016 at 16:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.