我有这个 Cursor 实现(API 10):
package com.blablabla.android.helpers.db.cursor;
import android.content.ContentResolver;
import android.database.AbstractWindowedCursor;
import android.database.CharArrayBuffer;
import android.database.ContentObserver;
import android.database.CrossProcessCursor;
import android.database.CursorWindow;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import com.blablabla.android.helpers.classloader.ClassLoaderHelper;
import com.blablabla.android.helpers.util.BijectiveHashMap;
import com.blablabla.android.helpers.util.BijectiveMap;
/**
* Cursor for IPC. Takes a CursorWindow as data buffer and the number of columns
* that CursorWindow has.
*
* @author me@blablabla.eu
*
*/
public class ParcelableCursor implements Parcelable, CrossProcessCursor {
/** Cursor data window */
protected CursorWindow window = CursorHelper.getCursorWindowInstance();
/** How many columns we have */
protected int numColumns = 0;
/** Column names */
protected BijectiveMap<String, Integer> colNames = new BijectiveHashMap<String, Integer>();
/** Current row */
protected int curRow = -1;
/** Is this cursor closed? */
protected boolean closed = false;
public ParcelableCursor() {
}
// /////////////////
// PARCELABLE IMPLEMENTATION
// /////////////////
/** CREATOR for Parcelable */
public static final Parcelable.Creator<ParcelableCursor> CREATOR = new Parcelable.Creator<ParcelableCursor>() {
public ParcelableCursor createFromParcel(Parcel in) {
return new ParcelableCursor(in);
}
public ParcelableCursor[] newArray(int size) {
return new ParcelableCursor[size];
}
};
/** Constructor for Parcelable */
public ParcelableCursor(Parcel in) {
readFromParcel(in);
}
@Override
public int describeContents() {
// Nothing to do here
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(window, 0);
out.writeInt(numColumns);
out.writeParcelable((Parcelable) colNames, 0);
out.writeInt(curRow);
out.writeByte(closed ? (byte) 1 : 0);
}
/** Restoring this object from a Parcel */
public void readFromParcel(Parcel in) {
window = in.readParcelable(CursorWindow.class.getClassLoader());
numColumns = in.readInt();
colNames = in.readParcelable(ClassLoaderHelper.getClassLoader());
curRow = in.readInt();
closed = (in.readByte() == 1);
}
// ////////////////
// END PARCELABLE IMPLEMENTATION
// ////////////////
// /////////////////
// CROSS PROCESS CURSOR IMPLEMENTATION
// /////////////////
@Override
public void close() {
window.close();
closed = true;
}
@Override
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
// TODO: what does this do?
}
@Override
public void deactivate() {
// Deprecated, does nothing
}
@Override
public byte[] getBlob(int columnIndex) {
return window.getBlob(curRow, columnIndex);
}
@Override
public int getColumnCount() {
return numColumns;
}
@Override
public int getColumnIndex(String columnName) {
int ret = -1;
Integer col = colNames.get(columnName);
if (col != null) {
ret = col;
}
return ret;
}
@Override
public int getColumnIndexOrThrow(String columnName)
throws IllegalArgumentException {
Integer col = colNames.get(columnName);
if (col == null) {
throw new IllegalArgumentException();
}
return col;
}
@Override
public String getColumnName(int columnIndex) {
return colNames.getKey(columnIndex);
}
@Override
public String[] getColumnNames() {
Log.d("PARCELCURSOR.getColumnNames()", "===GETTING COLNAMES===");
return colNames.keySet().toArray(new String[colNames.keySet().size()]);
}
@Override
public int getCount() {
return window.getNumRows();
}
@Override
public double getDouble(int columnIndex) {
return window.getDouble(curRow, columnIndex);
}
@Override
public Bundle getExtras() {
// TODO
return null;
}
@Override
public float getFloat(int columnIndex) {
return window.getFloat(curRow, columnIndex);
}
@Override
public int getInt(int columnIndex) {
return window.getInt(curRow, columnIndex);
}
@Override
public long getLong(int columnIndex) {
return window.getLong(curRow, columnIndex);
}
@Override
public int getPosition() {
return curRow;
}
@Override
public short getShort(int columnIndex) {
return window.getShort(curRow, columnIndex);
}
@Override
public String getString(int columnIndex) {
return window.getString(curRow, columnIndex);
}
@Override
public boolean getWantsAllOnMoveCalls() {
return false;
}
@Override
public boolean isAfterLast() {
return (curRow >= window.getNumRows());
}
@Override
public boolean isBeforeFirst() {
return (curRow < 0);
}
@Override
public boolean isClosed() {
return closed;
}
@Override
public boolean isFirst() {
return (curRow == 0);
}
@Override
public boolean isLast() {
return (curRow == window.getNumRows() - 1);
}
@Override
public boolean isNull(int columnIndex) {
return window.isNull(curRow, columnIndex);
}
@Override
public boolean move(int offset) {
int oldPos = curRow;
curRow += offset;
if (curRow < -1) {
curRow = -1;
return false;
} else if (curRow > window.getNumRows() - 1) {
curRow = window.getNumRows() - 1;
return false;
}
return onMove(oldPos, curRow);
}
@Override
public boolean moveToFirst() {
if (window.getNumRows() == 0) {
return false;
}
int oldPos = curRow;
curRow = 0;
return onMove(oldPos, curRow);
}
@Override
public boolean moveToLast() {
if (window.getNumRows() == 0) {
return false;
}
int oldPos = curRow;
curRow = window.getNumRows() - 1;
return onMove(oldPos, curRow);
}
@Override
public boolean moveToNext() {
int oldPos = curRow++;
if (isAfterLast()) {
curRow = window.getNumRows();
return false;
}
return onMove(oldPos, curRow);
}
@Override
public boolean moveToPosition(int position) {
if (position < -1 && position >= window.getNumRows()) {
return false;
}
int oldPos = curRow;
curRow = position;
return onMove(oldPos, curRow);
}
@Override
public boolean moveToPrevious() {
int oldPos = curRow--;
if (isBeforeFirst()) {
curRow = -1;
return false;
}
return onMove(oldPos, curRow);
}
/** Not supported */
@Override
public void registerContentObserver(ContentObserver observer) {
// Does nothing
}
/** Not supported */
@Override
public void registerDataSetObserver(DataSetObserver observer) {
// Does nothing
}
/** Deprecated, not supported */
@Override
public boolean requery() {
return false;
}
/** Not supported */
@Override
public Bundle respond(Bundle extras) {
// Does nothing
return null;
}
/** Not supported */
@Override
public void setNotificationUri(ContentResolver cr, Uri uri) {
// Does nothing
}
/** Not supported */
@Override
public void unregisterContentObserver(ContentObserver observer) {
// Does nothing
}
/** Not supported */
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
// Does nothing
}
@Override
public void fillWindow(int position, CursorWindow window) {
CursorHelper.copyCursorWindow(position, this.window, window);
}
@Override
public CursorWindow getWindow() {
CursorWindow ret = new CursorWindow(false);
fillWindow(0, ret);
return ret;
}
@Override
public boolean onMove(int oldPosition, int newPosition) {
// Don't forget to set curRow = -1 if this method returns false
return true;
}
// /////////////////
// END CROSS PROCESS CURSOR IMPLEMENTATION
// /////////////////
/** Sets this cursor using a CursorWindow data */
public void setFromWindow(CursorWindow window) {
CursorHelper.copyCursorWindow(0, window, this.window);
numColumns = CursorHelper.getCursorWindowNumCols(window);
moveToPosition(-1);
}
/** Sets this cursor from another windowed Cursor */
public void setFromCursor(AbstractWindowedCursor cursor) {
// Set column names
String[] colNames = cursor.getColumnNames();
for (String col : colNames) {
addColumn(col);
}
// Fill window
window.setNumColumns(numColumns);
cursor.fillWindow(0, window);
moveToPosition(-1);
}
/**
* Adds a new column at the end and assigns it this name. This will make
* this cursor to lose all its data, so you have to add all the columns
* before adding any row.
*/
private void addColumn(String name) {
numColumns++;
curRow = -1;
colNames.put(name, numColumns - 1);
}
}
我Cursor
通过Messenger
(实例内部Message
)和ContentProvider.query()
(和朋友)发送了一个实例。问题是该isNull()
方法在通过发送时可以正常工作,Cursor
但Messenger
在通过发送时总是返回 false ContentProvider
。
这是我的ContentProvider.query()
实现:
@Override
public Cursor query(final Uri uri, final String[] projection,
final String selection, final String[] selectionArgs,
final String sortOrder) {
// Build custom query object
final Query query = getBasicQuery(uri);
// .... More code preparing the query object
// Execute the query
dbManager.executeQuery(getSourceId(uri), query);
// This is a ParcelableCursor instance
final Cursor resultCursor = query.getResultCursor();
return resultCursor;
}
在这里,当我在ContentProvider
进程中运行时,该isNull()
方法可以正常工作,但是当Cursor
在客户端进程接收到时,它总是返回false
.
这是我做 aCursor.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)
编辑:经过大量调试,我可以看到当值为 时null
,isBlob()
返回true
。
关于这里可能出了什么问题的任何想法?