在进程之间传递游标(Parcelable Cursor) [英] Passing a Cursor between processes (Parcelable Cursor)

查看:404
本文介绍了在进程之间传递游标(Parcelable Cursor)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在API 10上将 Cursor SQLiteCursor )从服务传递到应用程序 ,并且很难找到一个体面的(和快速)解决方案。

I need to pass a Cursor (SQLiteCursor) from a service to an application on API 10, and having hard time finding a decent (and fast) solution.

我看到了 CursorWindow class。这是 Parcelable ,但我不能实例化这个类在API 10使用 SQLiteCursor.fillWindow()没有有效的构造函数。 CursorWindow(boolean)已弃用。

I've seen the CursorWindow class. This is Parcelable but I can't instantiate this class on API 10 to use SQLiteCursor.fillWindow() because it has no valid constructors. CursorWindow(boolean) is deprecated.

即使我有一个 CursorWindow SQLiteCursor 中的数据,如何将此窗口复制到新的 Cursor ?我应该使用什么 Cursor 实现?我看不到可扩展 AbstractWindowedCursor 的可用 Cursor

And even if I got a CursorWindow instance with data from a SQLiteCursor, how do I copy this window into a new Cursor? What Cursor implementation should I use for this? I see no usable Cursor that extends AbstractWindowedCursor.

感谢您的时间!

推荐答案

我实现了一个 ParcelableCursor CrossProcessCursor Parcelable 接口。如果任何人有兴趣,我会发布。一些操作不支持/实现,以及使用自定义 BijectiveMap (这是很容易实现)。

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!

编辑:这通过了很少的测试,所以测试之前使用它。

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

EDIT2:事实上,它有很多的bug ...我会尽快更新一个更少的bug版本。

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.

这篇关于在进程之间传递游标(Parcelable Cursor)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆