【问题标题】:Filtering a cursor the right way?以正确的方式过滤光标?
【发布时间】:2010-09-22 06:03:09
【问题描述】:

目前我需要过滤 Cursor/CursorAdapter 以仅显示与 ListView 中特定条件匹配的行。我不想一直重新查询数据库。我只想过滤从查询数据库中获得的光标。

我看到了问题:Filter rows from Cursor so they don't show up in ListView

但我不明白如何通过覆盖我的 CursorWrapper 中的“移动”方法来进行过滤。一个例子会很好。

非常感谢。

【问题讨论】:

  • 这个问题真的没有解决办法吗?

标签: android


【解决方案1】:

更新:

我已重写源代码,我的雇主已将其作为开源软件提供:https://github.com/clover/android-filteredcursor

您不需要重写 CursorWrapper 中的所有移动方法,但由于 Cursor 接口的设计,您确实需要重写一堆。假设您要过滤掉 7 行游标的第 2 行和第 4 行,创建一个扩展 CursorWrapper 的类并像这样覆盖这些方法:

private int[] filterMap = new int[] { 0, 1, 3, 5, 6 };
private int mPos = -1;

@Override
public int getCount() { return filterMap.length }

@Override
public boolean moveToPosition(int position) {
    // Make sure position isn't past the end of the cursor
    final int count = getCount();
    if (position >= 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;
    }
    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;
}

现在有趣的部分是创建 filterMap,这取决于您。

【讨论】:

  • 从您的回答来看,创建 filterMap 的一种自然方法似乎是将 Cursor 带入构造函数,在每个条目上使用过滤条件来确定是否将该行添加到 filterMap 或跳过它。现在你有了一个只会返回满足条件的条目的游标。
  • 谢谢,你是救命恩人! :)
  • 代码有一个错误,如果将光标移动到 -1 或计数(光标的两个有效位置。修复:@Override public boolean moveToPosition(int pos) { boolean moved; if (pos &gt;= getCount() || pos &lt; 0) { moved = super.moveToPosition(pos); } else { moved = super.moveToPosition(mFilterMap[pos]); } if (moved) mPos = pos; return moved; }
  • @zyamys 为什么不编辑答案以包含您的修复?
  • @Graham Borland - 我做了,但我的编辑被拒绝了。去图吧。
【解决方案2】:

我正在寻找类似的东西,就我而言,我想根据字符串比较过滤项目。我找到了这个要点https://gist.github.com/ramzes642/5400792,除非你开始玩弄光标的位置,否则它工作得很好。所以我找到了 satur9nine 的答案,他的一个尊重位置 api,但只需要根据光标进行一些调整来过滤,所以我将两者合并。您可以更改代码以适应它: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;i++) {
                super.moveToPosition(i);
                if (deAccent(this.getString(this.column)).toLowerCase().contains(this.filter)){
                    this.filterMap[filteredCount] = i;
                    filteredCount++;
                }
            }
            this.mCount = filteredCount;
        } else {
            this.filterMap = new int[count];
            this.mCount = count;
            for (int i=0;i<count;i++) {
                this.filterMap[i] = i;
            }
        }

        this.moveToFirst();
    }



    public int getCount() { return this.mCount; }

    @Override
    public boolean moveToPosition(int position) {
        Log.d(TAG,"moveToPosition:"+position);
        // Make sure position isn't past the end of the cursor
        final int count = getCount();
        if (position >= 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);
    }
}

【讨论】:

    【解决方案3】:

    我已经比较了遍历游标 1790 条目与游标中的查询 REGEXP,它是 1 分 15 秒和 15 秒。

    使用 REGEXP - 它更快。

    【讨论】:

      猜你喜欢
      • 2019-09-08
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-10
      • 2012-08-06
      相关资源
      最近更新 更多