5

API 10Cursorで( SQLiteCursor) をサービスからアプリケーションに渡す必要があり、まともな (そして高速な) ソリューションを見つけるのに苦労しています。

CursorWindow授業を見てきました。これは有効なコンストラクターがないためParcelable、API 10 でこのクラスをインスタンス化して使用することはできません。廃止されました。SQLiteCursor.fillWindow()CursorWindow(boolean)

CursorWindowからデータを含むインスタンスを取得した場合でも、SQLiteCursorこのウィンドウを新しい にコピーするにはどうすればよいCursorですか? これにはどのCursor実装を使用する必要がありますか? Cursor拡張する使用可能なものはありませんAbstractWindowedCursor

御時間ありがとうございます!

4

3 に答える 3

2

実装およびインターフェースするParcelableCursorクラスを実装しました。気になる人がいたら載せます。一部の操作はまだサポート/実装されておらず、カスタムを使用しています(これは非常に簡単に実装できます)。CrossProcessCursorParcelableBijectiveMap

/**
 * 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);
    }

}

これを行うためのより標準的な方法をまだ探しています。どんな情報でも大歓迎です!

編集:これはほとんどテストに合格していないため、使用する前にテストしてください。

EDIT2: 実際、それはバグでいっぱいです...バグの少ないバージョンですぐに更新します。

EDIT3: 1 年以来使用している作業カーソルで更新されました。

于 2012-08-03T14:36:11.803 に答える
1

私が抱えていた同様の問題を解決するために、 Parcelable Interfaceを実装する独自のカスタム クラスを作成しました。内部ではHashMapオブジェクトを実装するだけです。したがって、行の量について心配する必要はもうありません。カーソルを自分の ParcelableRow オブジェクトにマップするだけです。ここにmiコードがあります:

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);
}

}

これが誰かまたはあなた@m0skit0に役立つことを願っています。私のニーズを満たすことができるものを見つけるために数日を費やしました. ここに私が使用したいくつかのコード例があります。アドバイスは大歓迎です。

于 2013-03-09T03:32:49.613 に答える
1

コンテンツ プロバイダーを使用してデータを保存します。アプリケーションだけでなく、サービスからもアクセスできます。チュートリアル

于 2012-08-03T09:49:13.740 に答える