Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Recycler view adapter filter with animation

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++);
            }
        }
    }
like image 608
Harish Gyanani Avatar asked Dec 02 '16 09:12

Harish Gyanani


2 Answers

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

like image 175
wojciech_maciejewski Avatar answered Nov 09 '22 23:11

wojciech_maciejewski


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

 notifyItemRangeChanged(pos, ItemList.size());
like image 26
Ali Asheer Avatar answered Nov 10 '22 00:11

Ali Asheer