Android 从消息和ContentProvider调用时,光标行为会发生变化

Android 从消息和ContentProvider调用时,光标行为会发生变化,android,cursor,ipc,Android,Cursor,Ipc,我有这个游标实现(API 10): 在这里,当我在ContentProvider进程上运行时,isNull()方法工作正常,但是当客户端进程接收到光标时,它总是返回false 这是我执行Cursor.getString()时引发的异常,因为Cursor.isNull()返回(错误)false: 08-13 13:17:16.480: D/SELECT on ui(1572): java.lang.IllegalStateException: UNKNOWN type 0 08-13 13:17:

我有这个游标实现(API 10):

在这里,当我在
ContentProvider
进程上运行时,
isNull()
方法工作正常,但是当客户端进程接收到
光标时,它总是返回
false

这是我执行
Cursor.getString()
时引发的异常,因为
Cursor.isNull()
返回(错误)
false

08-13 13:17:16.480: D/SELECT on ui(1572): java.lang.IllegalStateException: UNKNOWN type 0
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWindow.getString_native(Native Method)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWindow.getString(CursorWindow.java:329)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:49)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWrapper.getString(CursorWrapper.java:135)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.blablabla.android.core.test.TestDBActivity.selectDB(TestDBActivity.java:332)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.blablabla.android.core.test.TestDBActivity$3.onClick(TestDBActivity.java:169)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.view.View.performClick(View.java:2485)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.view.View$PerformClick.run(View.java:9080)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Handler.handleCallback(Handler.java:587)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Handler.dispatchMessage(Handler.java:92)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Looper.loop(Looper.java:123)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.app.ActivityThread.main(ActivityThread.java:3683)
08-13 13:17:16.480: D/SELECT on ui(1572):         at java.lang.reflect.Method.invokeNative(Native Method)
08-13 13:17:16.480: D/SELECT on ui(1572):         at java.lang.reflect.Method.invoke(Method.java:507)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-13 13:17:16.480: D/SELECT on ui(1572):         at dalvik.system.NativeStart.main(Native Method)
EDIT:经过大量调试后,我可以看到当值为
null
时,
isBlob()
返回
true


你知道这里可能出了什么问题吗?

问题实际上出在
CursorHelper.copyCursorWindow()
,它是通过
fillWindow()
调用的,Android系统在
CursorWrapper
中调用它。这是我对这个方法的错误版本:

/**
 * Copies one CursorWindow into another. Previous data in destination
 * CursorWindow is lost
 * 
 * @param position
 *            Starting position to copy from the origin window
 * @param numColumns
 *            Number of columns in the origin window
 * @param origin
 *            CursorWindow to copy from
 * @param destination
 *            CursorWindow to copy to
 */
public static void copyCursorWindow(int position, CursorWindow origin,
        CursorWindow destination) {

    // Column number
    int numCols = getCursorWindowNumCols(origin);

    // Clear destination
    destination.clear();
    destination.setNumColumns(numCols);

    // Rows
    int i = position;
    while (i < origin.getNumRows() && destination.allocRow()) {

        // Columns
        for (int j = 0; j < numCols; j++) {

            if (origin.isBlob(i, j)) {
                byte[] cur = origin.getBlob(i, j);
                destination.putBlob(cur, i, j);

            } else if (origin.isFloat(i, j)) {
                Float cur = origin.getFloat(i, j);
                destination.putDouble(cur, i, j);

            } else if (origin.isLong(i, j)) {
                Long cur = origin.getLong(i, j);
                destination.putLong(cur, i, j);

            } else if (origin.isString(i, j)) {
                String cur = origin.getString(i, j);
                destination.putString(cur, i, j);

            } else if (origin.isNull(i, j)) {
                destination.putNull(i, j);
            }
        }
        i++;
    }
}
这是如何实现
isBlob()
的一个(恼人的)错误(虽然在API 11+中可能已修复,因为这部分有一些更改,比如
Cursor.getType()
method-)


()

实现与
SQLiteCursor
impl之间的主要区别。我可以看到的是您的
#getWindow()
实现,例如,一个
AbstractWindowedCursor
子类不会不断创建新的
窗口,而是保留一个实例。您的意思是我应该返回此对象拥有的
CursorWindow
?但如果其他对象使用此方法以意外的方式更改
CursorWindow
内容,则这可能是不可预测的。这与
isNull()
工作不正常也有什么关系?我看不到这个关系,我把它改成了简单的
返回窗口仍然是相同的问题。
08-13 13:17:16.480: D/SELECT on ui(1572): java.lang.IllegalStateException: UNKNOWN type 0
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWindow.getString_native(Native Method)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWindow.getString(CursorWindow.java:329)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:49)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWrapper.getString(CursorWrapper.java:135)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.blablabla.android.core.test.TestDBActivity.selectDB(TestDBActivity.java:332)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.blablabla.android.core.test.TestDBActivity$3.onClick(TestDBActivity.java:169)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.view.View.performClick(View.java:2485)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.view.View$PerformClick.run(View.java:9080)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Handler.handleCallback(Handler.java:587)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Handler.dispatchMessage(Handler.java:92)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Looper.loop(Looper.java:123)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.app.ActivityThread.main(ActivityThread.java:3683)
08-13 13:17:16.480: D/SELECT on ui(1572):         at java.lang.reflect.Method.invokeNative(Native Method)
08-13 13:17:16.480: D/SELECT on ui(1572):         at java.lang.reflect.Method.invoke(Method.java:507)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-13 13:17:16.480: D/SELECT on ui(1572):         at dalvik.system.NativeStart.main(Native Method)
/**
 * Copies one CursorWindow into another. Previous data in destination
 * CursorWindow is lost
 * 
 * @param position
 *            Starting position to copy from the origin window
 * @param numColumns
 *            Number of columns in the origin window
 * @param origin
 *            CursorWindow to copy from
 * @param destination
 *            CursorWindow to copy to
 */
public static void copyCursorWindow(int position, CursorWindow origin,
        CursorWindow destination) {

    // Column number
    int numCols = getCursorWindowNumCols(origin);

    // Clear destination
    destination.clear();
    destination.setNumColumns(numCols);

    // Rows
    int i = position;
    while (i < origin.getNumRows() && destination.allocRow()) {

        // Columns
        for (int j = 0; j < numCols; j++) {

            if (origin.isBlob(i, j)) {
                byte[] cur = origin.getBlob(i, j);
                destination.putBlob(cur, i, j);

            } else if (origin.isFloat(i, j)) {
                Float cur = origin.getFloat(i, j);
                destination.putDouble(cur, i, j);

            } else if (origin.isLong(i, j)) {
                Long cur = origin.getLong(i, j);
                destination.putLong(cur, i, j);

            } else if (origin.isString(i, j)) {
                String cur = origin.getString(i, j);
                destination.putString(cur, i, j);

            } else if (origin.isNull(i, j)) {
                destination.putNull(i, j);
            }
        }
        i++;
    }
}
/**
 * Copies one CursorWindow into another. Previous data in destination
 * CursorWindow is lost
 * 
 * @param position
 *            Starting position to copy from the origin window
 * @param numColumns
 *            Number of columns in the origin window
 * @param origin
 *            CursorWindow to copy from
 * @param destination
 *            CursorWindow to copy to
 */
public static void copyCursorWindow(int position, CursorWindow origin,
        CursorWindow destination) {

    // Column number
    int numCols = getCursorWindowNumCols(origin);

    // Clear destination
    destination.clear();
    destination.setNumColumns(numCols);

    // Rows
    int i = position;
    while (i < origin.getNumRows() && destination.allocRow()) {

        // Columns
        for (int j = 0; j < numCols; j++) {

            if (origin.isNull(i, j)) {
                destination.putNull(i, j);

            } else if (origin.isFloat(i, j)) {
                Float cur = origin.getFloat(i, j);
                destination.putDouble(cur, i, j);

            } else if (origin.isLong(i, j)) {
                Long cur = origin.getLong(i, j);
                destination.putLong(cur, i, j);

            } else if (origin.isString(i, j)) {
                String cur = origin.getString(i, j);
                destination.putString(cur, i, j);

            } else if (origin.isBlob(i, j)) {
                byte[] cur = origin.getBlob(i, j);
                destination.putBlob(cur, i, j);
            }
        }
        i++;
    }
}