Filtering a cursor the right way?

前端 未结 3 1557
我在风中等你
我在风中等你 2020-12-04 22:41

At the moment I need to filter a Cursor/CursorAdapter to only show rows that match a specific condition in the ListView. I don\'t want to requery the db all the time. I just

3条回答
  •  一生所求
    2020-12-04 23:37

    I was looking for something similar, in my case I wanted to filter items based on a string comparision. I found this gist https://gist.github.com/ramzes642/5400792, which works fine unless you start playing around with the position of the cursor. So I found satur9nine answer, his one respects the position api but just needs some adjustments for filtering based on cursor, so I merged the two. You can change your code to fit it: https://gist.github.com/rfreitas/ab46edbdc41500b20357

    import java.text.Normalizer;
    
    import android.database.Cursor;
    import android.database.CursorWrapper;
    import android.util.Log;
    
    
    //by Ricardo derfreitas@gmail.com
    //ref: https://gist.github.com/ramzes642/5400792 (the position retrieved is not correct)
    //ref: http://stackoverflow.com/a/7343721/689223 (doesn't do string filtering)
    //the two code bases were merged to get the best of both worlds
    //also added was an option to remove accents from UTF strings
    public class FilterCursorWrapper extends CursorWrapper {
        private static final String TAG = FilterCursorWrapper.class.getSimpleName();
        private String filter;
        private int column;
        private int[] filterMap;
        private int mPos = -1;
        private int mCount = 0;
    
        public FilterCursorWrapper(Cursor cursor,String filter,int column) {
            super(cursor);
            this.filter = deAccent(filter).toLowerCase();
            Log.d(TAG, "filter:"+this.filter);
            this.column = column;
            int count = super.getCount();
    
            if (!this.filter.isEmpty()) {
                this.filterMap = new int[count];
                int filteredCount = 0;
                for (int i=0;i= count) {
                mPos = count;
                return false;
            }
            // Make sure position isn't before the beginning of the cursor
            if (position < 0) {
                mPos = -1;
                return false;
            }
            final int realPosition = filterMap[position];
            // When moving to an empty position, just pretend we did it
            boolean moved = realPosition == -1 ? true : super.moveToPosition(realPosition);
            if (moved) {
                mPos = position;
            } else {
                mPos = -1;
            }
            Log.d(TAG,"end moveToPosition:"+position);
            return moved;
        }
        @Override
        public final boolean move(int offset) {
            return moveToPosition(mPos + offset);
        }
        @Override
        public final boolean moveToFirst() {
            return moveToPosition(0);
        }
        @Override
        public final boolean moveToLast() {
            return moveToPosition(getCount() - 1);
        }
        @Override
        public final boolean moveToNext() {
            return moveToPosition(mPos + 1);
        }
        @Override
        public final boolean moveToPrevious() {
            return moveToPosition(mPos - 1);
        }
        @Override
        public final boolean isFirst() {
            return mPos == 0 && getCount() != 0;
        }
        @Override
        public final boolean isLast() {
            int cnt = getCount();
            return mPos == (cnt - 1) && cnt != 0;
        }
        @Override
        public final boolean isBeforeFirst() {
            if (getCount() == 0) {
                return true;
            }
            return mPos == -1;
        }
        @Override
        public final boolean isAfterLast() {
            if (getCount() == 0) {
                return true;
            }
            return mPos == getCount();
        }
        @Override
        public int getPosition() {
            return mPos;
        }
    
        //added by Ricardo
        //ref: http://stackoverflow.com/a/22612054/689223
        //other: http://stackoverflow.com/questions/8523631/remove-accents-from-string
        //other: http://stackoverflow.com/questions/15190656/easy-way-to-remove-utf-8-accents-from-a-string
        public static String deAccent(String str) {
            //return StringUtils.stripAccents(str);//this method from apache.commons respects chinese characters, but it's slower than flattenToAscii
            return flattenToAscii(str);
        }
    
        //ref: http://stackoverflow.com/a/15191508/689223
        //this is the fastest method using the normalizer found yet, the ones using Regex are too slow
        public static String flattenToAscii(String string) {
            char[] out = new char[string.length()];
            string = Normalizer.normalize(string, Normalizer.Form.NFD);
            int j = 0;
            for (int i = 0, n = string.length(); i < n; ++i) {
                char c = string.charAt(i);
                int type = Character.getType(c);
                if (type != Character.NON_SPACING_MARK){
                    out[j] = c;
                    j++;
                }
            }
            return new String(out);
        }
    }
    

提交回复
热议问题