Passing a Cursor between processes (Parcelable Cursor)

一个人想着一个人 提交于 2019-12-03 16:02:50

I implemented a ParcelableCursor class that implements CrossProcessCursor and Parcelable interfaces. I'll post it if anyone is interested. Some operations are not supported/implemented yet, as well as using a custom BijectiveMap (which is quite easy to implement).

/**
 * Prefer ParcelableCursorForIntent instead.<br/>
 * Cursor for IPC. Takes a CursorWindow as data buffer and the number of columns
 * that CursorWindow has.<br/>
 * <br/>
 * <b>NOTE: this Cursor cannot be parceled when sending by intents due to <a
 * href="http://code.google.com/p/android/issues/detail?id=4470">an Android
 * bug</a>. Please use ParcelableCursorForIntent instead.</b>
 * 
 * @author m0skit0@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;

    /** CREATOR for Parcelable */
    public static final Parcelable.Creator<ParcelableCursor> CREATOR = new Parcelable.Creator<ParcelableCursor>() { // NOPMD
                                                                                                                    // AM
        @Override
        public ParcelableCursor createFromParcel(final Parcel in) {
            return new ParcelableCursor(in);
        }

        @Override
        public ParcelableCursor[] newArray(final int size) {
            return new ParcelableCursor[size];
        }
    };

    /**
     * Creates an empty ParcelableCursor. Please consider to use
     * {@link #setFromCursor(AbstractWindowedCursor)} or
     * {@link #setFromWindow(CursorWindow)} to initialize it.
     */
    public ParcelableCursor() {
        // Empty ParcelableCursor, don't forget to use #setFromCursor
    }

    /** Constructor for Parcelable */
    public ParcelableCursor(final Parcel in) {
        readFromParcel(in); // NOPMD by yasin on 12/7/12 11:55 AM - Android's
        // Parceleble
    }

    /**
     * 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(final String name) {
        this.numColumns++;
        this.curRow = -1;
        this.colNames.put(name, this.numColumns - 1);
    }

    @Override
    public void close() {
        this.window.close();
        this.closed = true;
    }

    @Override
    public void copyStringToBuffer(final int columnIndex,
            final CharArrayBuffer buffer) {
        // TODO: what does this do?
    }

    @Override
    public void deactivate() {
        // Deprecated, does nothing
    }

    @Override
    public int describeContents() {
        // Nothing to do here
        return 0;
    }

    @Override
    public void fillWindow(final int position, final CursorWindow window) {
        CursorHelper.copyCursorWindow(position, this.window, window);
    }

    @Override
    public byte[] getBlob(final int columnIndex) {
        return this.window.getBlob(this.curRow, columnIndex);
    }

    @Override
    public int getColumnCount() {
        return this.numColumns;
    }

    @Override
    public int getColumnIndex(final String columnName) {
        int ret = -1;
        final Integer col = this.colNames.get(columnName);
        if (col != null) {
            ret = col;
        }
        return ret;
    }

    @Override
    public int getColumnIndexOrThrow(final String columnName)
            throws IllegalArgumentException {
        final Integer col = this.colNames.get(columnName);
        if (col == null) {
            throw new IllegalArgumentException();
        }
        return col;
    }

    @Override
    public String getColumnName(final int columnIndex) {
        return this.colNames.getKey(columnIndex);
    }

    @Override
    public String[] getColumnNames() {
        if (DebugConfig.DEBUG) {
            Log.d("PARCELCURSOR.getColumnNames()---", "===GETTING COLNAMES===");
        }

        final Set<Entry<String, Integer>> set = this.colNames.entrySet();
        final String[] colArray = new String[set.size()];
        for (final String colName : this.colNames.keySet()) {
            if (DebugConfig.DEBUG) {
                Log.d("-------------PARCELCURSOR.getColumnNames()", colName);
            }
            final int pos = this.colNames.get(colName);
            colArray[pos] = colName;
        }

        return colArray;
    }

    @Override
    public int getCount() {
        return this.window.getNumRows();
    }

    @Override
    public double getDouble(final int columnIndex) {
        return this.window.getDouble(this.curRow, columnIndex);
    }

    @Override
    public Bundle getExtras() {
        // Does not support Extras
        return null;
    }

    @Override
    public float getFloat(final int columnIndex) {
        return this.window.getFloat(this.curRow, columnIndex);
    }

    @Override
    public int getInt(final int columnIndex) {
        return this.window.getInt(this.curRow, columnIndex);
    }

    @Override
    public long getLong(final int columnIndex) {
        return this.window.getLong(this.curRow, columnIndex);
    }

    @Override
    public int getPosition() {
        return this.curRow;
    }

    @Override
    public short getShort(final int columnIndex) { // NOPMD by yasin on 12/7/12
                                                    // 11:57 AM - Override
        return this.window.getShort(this.curRow, columnIndex);
    }

    @Override
    public String getString(final int columnIndex) {
        return this.window.getString(this.curRow, columnIndex);
    }

    @SuppressLint("NewApi")
    @Override
    public int getType(final int columnIndex) {
        final int currentapiVersion = android.os.Build.VERSION.SDK_INT;

        int result = 0;

        if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            result = this.window.getType(this.curRow, columnIndex);
        } else {
            if (this.window.isNull(this.curRow, columnIndex)) {
                result = 0; // FIELD_TYPE_NULL;
            } else if (this.window.isFloat(this.curRow, columnIndex)) {
                result = 2; // FIELD_TYPE_FLOAT;
            } else if (this.window.isLong(this.curRow, columnIndex)) {
                result = 1; // FIELD_TYPE_INTEGER;
            } else if (this.window.isString(this.curRow, columnIndex)) {
                result = 3; // FIELD_TYPE_STRING;
            } else if (this.window.isBlob(this.curRow, columnIndex)) {
                result = 4; // FIELD_TYPE_BLOB;
            }
        }

        return result;
    }

    @Override
    public boolean getWantsAllOnMoveCalls() {
        return false;
    }

    @Override
    public CursorWindow getWindow() {
        final CursorWindow ret = CursorHelper.getCursorWindowInstance();
        fillWindow(0, ret);
        return ret;
    }

    @Override
    public boolean isAfterLast() {
        return (this.curRow >= this.window.getNumRows());
    }

    @Override
    public boolean isBeforeFirst() {
        return (this.curRow < 0);
    }

    @Override
    public boolean isClosed() {
        return this.closed;
    }

    @Override
    public boolean isFirst() {
        return (this.curRow == 0);
    }

    @Override
    public boolean isLast() {
        return (this.curRow == this.window.getNumRows() - 1);
    }

    @Override
    public boolean isNull(final int columnIndex) {
        return this.getType(columnIndex) == FIELD_TYPE_NULL;
    }

    @Override
    public boolean move(final int offset) {
        final int oldPos = this.curRow;
        this.curRow += offset;
        if (this.curRow < -1) {
            this.curRow = -1;
            return false;
        } else if (this.curRow > this.window.getNumRows() - 1) {
            this.curRow = this.window.getNumRows() - 1;
            return false;
        }
        return onMove(oldPos, this.curRow);
    }

    @Override
    public boolean moveToFirst() {
        if (this.window.getNumRows() == 0) {
            return false;
        }
        final int oldPos = this.curRow;
        this.curRow = 0;
        return onMove(oldPos, this.curRow);
    }

    @Override
    public boolean moveToLast() {
        if (this.window.getNumRows() == 0) {
            return false;
        }
        final int oldPos = this.curRow;
        this.curRow = this.window.getNumRows() - 1;
        return onMove(oldPos, this.curRow);
    }

    @Override
    public boolean moveToNext() {
        final int oldPos = this.curRow++;
        if (isAfterLast()) {
            this.curRow = this.window.getNumRows();
            return false;
        }
        return onMove(oldPos, this.curRow);
    }

    @Override
    public boolean moveToPosition(final int position) {
        if (position < -1 && position >= this.window.getNumRows()) {
            return false;
        }
        final int oldPos = this.curRow;
        this.curRow = position;
        return onMove(oldPos, this.curRow);
    }

    @Override
    public boolean moveToPrevious() {
        final int oldPos = this.curRow--;
        if (isBeforeFirst()) {
            this.curRow = -1;
            return false;
        }
        return onMove(oldPos, this.curRow);
    }

    @Override
    public boolean onMove(final int oldPosition, final int newPosition) {
        // Don't forget to set curRow = -1 if this method returns false
        return true;
    }

    /** Restoring this object from a Parcel */
    public void readFromParcel(final Parcel in) {

        this.numColumns = in.readInt();
        this.colNames = in.readParcelable(ClassLoaderHelper.getClassLoader());
        this.curRow = in.readInt();
        this.closed = (in.readByte() == 1);
        // Closes the cursor before create a new cursor.
        if (window != null) {
            window.close();
        }
        this.window = CursorWindow.newFromParcel(in);
    }

    /** Not supported */
    @Override
    public void registerContentObserver(final ContentObserver observer) {
        // Does nothing
    }

    /** Not supported */
    @Override
    public void registerDataSetObserver(final DataSetObserver observer) {
        // Does nothing
    }

    /** Deprecated, not supported */
    @Override
    public boolean requery() {
        return false;
    }

    /** Not supported */
    @Override
    public Bundle respond(final Bundle extras) {
        // Does nothing
        return null;
    }

    /** Sets this cursor from another windowed Cursor */
    public void setFromCursor(final AbstractWindowedCursor cursor) throws CursorIndexOutOfBoundsException, IllegalStateException {

        // Reset number of columns
        this.numColumns = 0;

        // Set column names
        final String[] colNames = cursor.getColumnNames();
        if (colNames != null) {
            for (final String col : colNames) {
                addColumn(col);
            }
        }

        // Fill window
        this.window.clear();
        this.window.setNumColumns(this.numColumns);
        cursor.fillWindow(0, this.window);
        moveToPosition(-1);
    }

    /** Sets this cursor from another windowed Cursor */
    public void setFromCursor(final MatrixCursor cursor) throws CursorIndexOutOfBoundsException ,IllegalStateException{

        // Reset number of columns
        this.numColumns = 0;

        // Set column names
        final String[] colNames = cursor.getColumnNames();
        if (colNames != null) {
            for (final String col : colNames) {
                addColumn(col);
            }
        }

        // Fill window
        this.window.clear();
        this.window.setNumColumns(this.numColumns);
        cursor.fillWindow(0, this.window);
        moveToPosition(-1);
    }

    /** Sets this cursor using a CursorWindow data */
    public void setFromWindow(final CursorWindow window) {
        CursorHelper.copyCursorWindow(0, window, this.window);
        this.numColumns = CursorHelper.getCursorWindowNumCols(window);
        moveToPosition(-1);
    }

    /** Not supported */
    @Override
    public void setNotificationUri(final ContentResolver cr, final Uri uri) {
        // Does nothing
    }

    /** Not supported */
    @Override
    public void unregisterContentObserver(final ContentObserver observer) {
        // Does nothing
    }

    /** Not supported */
    @Override
    public void unregisterDataSetObserver(final DataSetObserver observer) {
        // Does nothing
    }

    @Override
    public void writeToParcel(final Parcel out, final int flags) {

        out.writeInt(this.numColumns);
        out.writeParcelable((Parcelable) this.colNames, 0);
        out.writeInt(this.curRow);
        out.writeByte(this.closed ? (byte) 1 : 0);
        this.window.writeToParcel(out, flags);
    }

}

Still looking for a more standard way to do this. Any information would be appreciated greatly!

EDIT: this passed very few tests, so test it before using it.

EDIT2: in fact, it's full of bugs... I'll update with a less buggy version soon.

EDIT3: updated with working cursor we are using since one year.

Use Content Provider to store your data. You can access it from service as well as from application. tutorial

AXSM

To solve a similar problem which i had, i made my own custom class which implements a Parcelable Interface. and inside i just implement HashMap object. So i don't jave to worry anymore about amount of rows, i just map the cursor to my own ParcelableRow object. here is mi code:

public class ParcelableRow implements Parcelable {
 private HashMap<String, String> colsMap;


 public static final Parcelable.Creator<ParcelableRow> CREATOR
 = new Parcelable.Creator<ParcelableRow>() {

    @Override
    public ParcelableRow createFromParcel(Parcel source) {
        return new ParcelableRow(source);
    }

    @Override
    public ParcelableRow[] newArray(int size) {
        return new ParcelableRow[size];
    }
};


public ParcelableRow(Parcel in) {
    colsMap = new HashMap<String, String>();
    readFromParcel(in);
}
public ParcelableRow() {
    colsMap = new HashMap<String, String>();
}
@Override
public int describeContents() {
    return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {

    for(String key: colsMap.keySet()){

        dest.writeString(key);
        dest.writeString(colsMap.get(key));

    }

}
public void readFromParcel(Parcel parcel) {

    int limit = parcel.dataSize();
    parcel.setDataPosition(0);
    for(int i = 0; i < limit; i++){
        colsMap.put(parcel.readString(), parcel.readString());
    }

}


public void addNewCol(String colName, String colValue){
    colsMap.put(colName, colValue);
}
public String getColumnValue(String colName){
    return colsMap.get(colName);
}

}

I hope this can be useful to someone or you @m0skit0, i've just spend some days trying to find something that could satisfy my needs. here are some code examples which i've used. advises are welcome.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!