android.database.CursorWindowAllocationException:

2019-03-18 13:30发布

问题:

There are many questions on SO about CursorWindowAllocatoinException:

  • SQLite Android Database Cursor window allocation of 2048 kb failed
  • Could not allocate CursorWindow
  • Out of Memory when allocating cursors
  • Android SQLite CursorWindowAllocationException crash

All of them suggest that cursor must be closed after use. But that did not resolve my problem. Here is my code:

String query = "select serial from tbl1 union select serial from tbl2 union select serial from tbl3";
    SQLiteDatabase db = null;
    Cursor cur = null;
    try {
        SettingsDatabaseHelper dal = new SettingsDatabaseHelper(
                c);
        db = dal.getReadableDatabase();
        cur = db.rawQuery(query, null);
        int numRows = cur.getCount();
        if (numRows > 0) {
            cur.moveToFirst();

            int serialIdx = cur.getColumnIndexOrThrow("serial");
            for (boolean hasItem = cur.moveToFirst(); hasItem; hasItem = cur
                    .moveToNext()) {

                String serial = cur.getString(serialIdx);
                if (Validator.getInstance().isValidSerial(serial))
                    serials.add(serial);

            }
        }
    } finally {
        if (cur != null)
            cur.close();

        if (db != null)
            db.close();
    }

I run this method every few seconds. After half an hour, I get CursorWindowAllocationException in int numRows=cur.getCount(); and then my service stops.

Since I am closing the cursor, there may be a problem with my Helper class. Here is the code:

public class SettingsDatabaseHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "mydb.db";
    private static final int DATABASE_VERSION = 1;


    private static final String TBL_CREATE="create table...";



    public SettingsDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase database) {
        database.execSQL(TBL_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        onCreate(db);
    }
}

How can I prevent this exception from being thrown?

回答1:

I was querying the database from a service. When I did it from an activity, the problem never occurred again.

Alongside querying, I was reading from the serial port within the same service. Maybe that caused the problem. However, when I used an activity instead of the service, the problem never happened again.



回答2:

i had the same problem in my application while loading more than 500 songs from android media store.

closing the cursor will not solve your problem.

you should use AsyncTask.. inside doInBackground method write the code for retrieving values from cursor.

public class CursorLoader extends AsyncTask {

    @Override
    protected Void doInBackground(Void... params) {

        String query = "select serial from tbl1 union select serial from tbl2 union select serial from tbl3";
SQLiteDatabase db = null;
Cursor cur = null;
try {
    SettingsDatabaseHelper dal = new SettingsDatabaseHelper(
            c);
    db = dal.getReadableDatabase();
    cur = db.rawQuery(query, null);
    int numRows = cur.getCount();
    if (numRows > 0) {
        cur.moveToFirst();

        int serialIdx = cur.getColumnIndexOrThrow("serial");
        for (boolean hasItem = cur.moveToFirst(); hasItem; hasItem = cur
                .moveToNext()) {

            String serial = cur.getString(serialIdx);
            if (Validator.getInstance().isValidSerial(serial))
                serials.add(serial);

        }
    }
} finally {
    if (cur != null)
        cur.close();

    if (db != null)
        db.close();
}

        return null;
    }

    @Override
    protected void onPreExecute() {

    }



    @Override
    protected void onPostExecute(Void result) {


}


回答3:

I had the same problem, while i am calling the DATA BASE, in the service class using forever loop.

My code was like:

service ()
 {
void run()
   {
     while(conditionisTrue)
       {
              db.getRecord();  //I remove this code from here and put it in the start of service c
        }
    }
 }