2

SQLite データベースにデータを保存するための以下のクラスを作成しました。ご覧のとおり、これは単なるキーと値のマッピングです。KEY は TEXT フィールドで、VALUE は BLOB です。

1 つのシナリオを除いて、完全に機能します。「add」を使用して、長さが約 2,500,000 文字の文字列を追加します。実際、これは JSON でエンコードされた文字列です (干渉する不正な文字がないことを確認するために、javascript スタイルの encodeURIComponent も適用しようとしました)。

このシナリオでは、値が正常に追加されます (エラーはスローされず、add() は true を返します)。しかし、その直後に get(key) を呼び出すと、cursor.getString(0) から IllegalStateException がスローされます。

具体的には:

"Couldn't read row 0, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it." (id=830026207728) 

カーソル オブジェクトを調べましたが、問題はありません (mCount==1、mColumns==String[1] など)。

class DatabaseHandler extends SQLiteOpenHelper {

    // All Static variables
    // Database Version
    private static final int DATABASE_VERSION = 2;

    // Contacts Table Columns names
    private static final String KEY_KEY = "key";
    private static final String KEY_VAL = "value";

    public DatabaseHandler(Context context) {
        super(context, Defines.DATA_PREFIX, null, DATABASE_VERSION);
    }

    public String getTableName() {
        return "storage";
    }

    // Creating Tables
    @Override
    public void onCreate(SQLiteDatabase db) {
        String q = "CREATE TABLE " + this.getTableName() + "(" + KEY_KEY + " TEXT PRIMARY KEY," + KEY_VAL + " BLOB" + ")";
        db.execSQL(q);
    }

    // Upgrading database
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // Drop older table if existed
        db.execSQL("DROP TABLE IF EXISTS " + this.getTableName());

        // Create tables again
        onCreate(db);
    }

    boolean add(String key, String value) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_KEY, key); // Contact Name
        values.put(KEY_VAL, value); // Contact Phone

        // Inserting Row
        long res = db.insertOrThrow(this.getTableName(), null, values);
        db.close(); // Closing database connection
        return res >= 0;
    }

    String get(String key) {
        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor = db.query(this.getTableName(), new String[] { KEY_VAL }, KEY_KEY + "=?", new String[] { key }, null, null, null, null);
        if (cursor != null)
            cursor.moveToFirst();

        if(cursor == null)
            return null;

        String ret = null;
        try {
            ret = cursor.getString(0);
        } catch(CursorIndexOutOfBoundsException e) {
            ret = null;
        } catch(IllegalStateException e) {
            ret = null;
        }
        cursor.close();
        return ret;
    }

    int count(String key) {
        String countQuery = "SELECT  * FROM " + this.getTableName()+" WHERE "+KEY_KEY+" = ?";
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(countQuery, new String[] { key });
        int ret = cursor.getCount();;
        cursor.close();

        // return count
        return ret;
    }

    void delete(String key) {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete(this.getTableName(), KEY_KEY + " = ?", new String[] { key });
        db.close();
    }

    int update(String key, String value)
    {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_KEY, key);
        values.put(KEY_VAL, value);

        // updating row
        return db.update(this.getTableName(), values, KEY_KEY + " = ?", new String[] { key });
    }
}
4

1 に答える 1

3

さらに調査したところ、コンソール ウィンドウに、「カーソル ウィンドウ」がいっぱいであることが表示されました。たとえば、スペースがありませんでした。このスレッドを参照してください: Android: カーソル ウィンドウがいっぱいです

私の解決策は、データを「チャンク」することでした。たとえば、"add" 関数は、文字列が > 固定長であるかどうかを検出します。その場合、文字列に対して複数のエントリを格納します (多くの行を使用します)。次に、「get」関数がこれを検出し、チャンクを再構築します。

于 2012-09-02T03:00:39.240 に答える