RuntimeException on cursor.getCount()

时间:2016-12-23 09:32:30

标签: android sqlite

Fabric reported me this error, so I really don't know when and how it could be caused. Maybe the user stopped the application while accessing the DB...

The code is:

private void addOrUpdateJoinTable(SQLiteDatabase db, long site_id, JSONArray myJSONCategoriesArray) throws JSONException {

    ContentValues newCategoriesValues = new ContentValues();
    Cursor cursor = null;

    try {
        for (int i = 0; i < myJSONCategoriesArray.length(); i++) {

            JSONObject jsCategory = myJSONCategoriesArray.getJSONObject(i);

            cursor = db.rawQuery(
                    "SELECT " +
                            SitesDBOpenHelper.DATABASE_SITES_CATEGORIES_TABLE + "." + SitesDBOpenHelper.KEY_ID +  ", " +
                            SitesDBOpenHelper.DATABASE_SITES_TABLE + "." + SitesDBOpenHelper.KEY_ID + " AS S_id, " +
                            SitesDBOpenHelper.DATABASE_CATEGORIES_TABLE + "." + SitesDBOpenHelper.KEY_ID + " AS C_id " +
                            " FROM " +
                            SitesDBOpenHelper.DATABASE_SITES_TABLE +
                            " INNER JOIN " +
                            SitesDBOpenHelper.DATABASE_SITES_CATEGORIES_TABLE + " ON " +
                            SitesDBOpenHelper.DATABASE_SITES_CATEGORIES_TABLE + "." + SitesDBOpenHelper.KEY_SITE_ID + " = S_id " +
                            " INNER JOIN " +
                            SitesDBOpenHelper.DATABASE_CATEGORIES_TABLE + " ON " +
                            "C_id = " +
                            SitesDBOpenHelper.DATABASE_SITES_CATEGORIES_TABLE + "." + SitesDBOpenHelper.KEY_CATEGORY_ID +
                            " WHERE " +
                            "S_id = ?" +
                            " AND " +
                            SitesDBOpenHelper.DATABASE_CATEGORIES_TABLE + "." + SitesDBOpenHelper.KEY_CODE + " = ?",
                    new String[] {Long.toString(site_id), jsCategory.get(SitesDBOpenHelper.KEY_CODE).toString()}
            );


            if ((cursor != null) && (cursor.getCount() > 0)) {

                cursor.moveToFirst();

                long id = cursor.getLong(cursor.getColumnIndex(SitesDBOpenHelper.KEY_ID));

                newCategoriesValues.put(SitesDBOpenHelper.KEY_SITE_ID, cursor.getLong(cursor.getColumnIndex("S_id")));
                newCategoriesValues.put(SitesDBOpenHelper.KEY_CATEGORY_ID, cursor.getLong(cursor.getColumnIndex("C_id")));

                result = db.update(SitesDBOpenHelper.DATABASE_SITES_CATEGORIES_TABLE, newCategoriesValues, SitesDBOpenHelper.KEY_ID + " = ?", new String[]{Long.toString(id)});

                if (debug) Log.d(Constants.APP_TAG, "update " + newCategoriesValues.toString());
            } else {

                String resultSites_columns[] = new String[] {
                        SitesDBOpenHelper.KEY_ID,
                        SitesDBOpenHelper.KEY_CODE,
                };

                String where = SitesDBOpenHelper.KEY_CODE
                        + " = ?";

                String whereArgs[] = {jsCategory.get(SitesDBOpenHelper.KEY_CODE).toString()};

                cursor = db.query(SitesDBOpenHelper.DATABASE_CATEGORIES_TABLE, resultSites_columns, where, whereArgs, null, null, null);

                if ((cursor != null) && (cursor.getCount() > 0)) {

                    //dumpCursor(cursor);

                    cursor.moveToFirst();

                    newCategoriesValues.put(SitesDBOpenHelper.KEY_SITE_ID, site_id);

                    newCategoriesValues.put(SitesDBOpenHelper.KEY_CATEGORY_ID, cursor.getLong(cursor.getColumnIndex(SitesDBOpenHelper.KEY_ID)));

                    db.insert(SitesDBOpenHelper.DATABASE_SITES_CATEGORIES_TABLE, null, newCategoriesValues);

                    if (debug) Log.d(Constants.APP_TAG, "insert " + newCategoriesValues.toString());
                } else {

                    if (debug) Log.d(Constants.APP_TAG, "!! category not found !! " + jsCategory.get(SitesDBOpenHelper.KEY_CODE).toString());

                }

            }
        }

    } catch (NumberFormatException e) {
        if (debug) Log.d(Constants.APP_TAG, "NumberFormatException " + e);
    }catch (SQLiteException e) {
        if (debug) Log.d(Constants.APP_TAG, "SQLLiteException " + e);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

The error is:

Fatal Exception: java.lang.RuntimeException: An error occured while executing doInBackground()
       at android.os.AsyncTask$3.done(AsyncTask.java:300)
       at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
       at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
       at java.util.concurrent.FutureTask.run(FutureTask.java:242)
       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:818)
Caused by android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=649 (# cursors opened by this proc=649)
       at android.database.CursorWindow.<init>(CursorWindow.java:108)
       at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
       at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:139)
       at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
       at com.my.example.LoadSitesListTask.addOrUpdateJoinTable(LoadSitesListTask.java:1461)
       at com.my.example.LoadSitesListTask.updateDBFromJSONData(LoadSitesListTask.java:1152)
       at com.my.example.LoadSitesListTask.doInBackground(LoadSitesListTask.java:153)
       at com.my.example.LoadSitesListTask.doInBackground(LoadSitesListTask.java:58)
       at android.os.AsyncTask$2.call(AsyncTask.java:288)
       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:818)

Could anyone tell me something on such kind of error? Is it "normal" if the user stopped the app while working? or is it possible to prevent such cases?

One strange thing anyway is the allocation of 2048 kb requested for the cursor. You can see that based on the resultSites_columns containing 2 integers, 2048 kb doesn't make sense.

Does it mean something?

1 个答案:

答案 0 :(得分:0)

问题是游标没有关闭。你在try-finally块中有一个循环,但问题是你打开myJSONCategoriesArray.length()游标,但只关闭最后一个游标,即在循环的最后一次迭代中分配给cursor的游标。

您需要做的是在循环中移动try-finally块:

for (int i = 0; i < myJSONCategoriesArray.length(); i++) {
    Cursor cursor = db.rawQuery(/* rest omitted */);
    try {
        // Use the cursor
    } finally {
        if (cursor != null) cursor.close();
    }
}

这样你就可以关闭所有游标,而不仅仅是最后一个游标。