Что может быть причиной этого SQLite CursorWindowAllocationException?

Моя консоль разработчика Google Play сообщила о своем первом сбое в работе моего приложения для Android. Похоже, что SQLite не удалось выделить память для курсора, но я никогда не видел этого раньше и не могу воспроизвести его. Есть идеи?

Google Stackgrace сообщает:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.NsouthProductions.gradetrackerpro/com.NsouthProductions.gradetrackerpro.Activity_Category}: android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=530 (# cursors opened by this proc=530)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2305)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
at android.app.ActivityThread.access$900(ActivityThread.java:161)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5356)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=530 (# cursors opened by this proc=530)
at android.database.CursorWindow.<init>(CursorWindow.java:108)
at android.database.CursorWindow.<init>(CursorWindow.java:100)
at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
at android.database.sqlite.SQLiteCursor.clearOrCreateWindow(SQLiteCursor.java:301)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:139)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:197)
at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:237)
at com.NsouthProductions.gradetrackerpro.DBAdapter.getCourse(DBAdapter.java:401)
at com.NsouthProductions.gradetrackerpro.Activity_Category$CategoryActivityFragment.setListData(Activity_Category.java:196)
at com.NsouthProductions.gradetrackerpro.Activity_Category$CategoryActivityFragment.onCreateView(Activity_Category.java:182)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1500)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:938)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1115)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1478)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:570)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1189)
at android.app.Activity.performStart(Activity.java:5436)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
... 11 more

Где это не удалось в моем классе DBAdapter.

public Course getCourse (int rowId) throws SQLException {
        Cursor c =
                db.query(true, TABLE_COURSES, new String[] {KEY_ID, KEY_TITLE,
                KEY_YEAR, KEY_SEASON, KEY_CREDIT}, KEY_ID + "=" + rowId, null, null, null, null, null);
        if (c != null) {
            c.moveToFirst();
        }
        Course course = new Course(c.getInt(0), c.getString(1), c.getInt(2), c.getString(3), c.getDouble(4));
        return course;
    }

Где вызывается функция DBAdapter. На этом этапе операции БД уже была успешно открыта, запрошена и закрыта.

public void setListData(){
            db.open();
            Grade[] g = db.getGradesInCategory(catId);
            this.getActivity().setTitle(db.getCourse(courseId).getTitle());
            db.close();

3 ответа

Решение

Это OutOfMemoryError, в результате. Цитирование комментариев для этого класса исключений:

Это исключение выдается, когда CursorWindow не может быть выделено, скорее всего из-за недоступности памяти.

Сообщение об ошибке показывает, что у вас открыт 530 Cursor объекты, которые могут быть частью вашей проблемы. Например, вы просачиваете Cursor в вашем getCourse() метод. Убедитесь, что вы закрыли Cursor как только вы закончите с этим.

Если это не поможет, вам нужно относиться к этому как OutOfMemoryError и определить, где еще вы тратите кучу места, возможно, с помощью таких инструментов, как MAT.

Курсоры должны быть закрыты:

Cursor c = db.query(...);
try {
    ...
} finally {
    c.close();
}

Если вы не хотите возиться с несколькими локальными переменными для возврата, вы можете вернуть объект Cursor, а затем закрыть его из вызывающего метода.

Это в ответ на "Хм. Иногда я использую return cursor.getString(0). Я думаю, я не могу ни закрыть курсор после возврата, ни вернуться, используя его после закрытия. Мне придется возвращать временные переменные, верно? - 4 октября 14 августа в 20:44: &

@NSouth: "Мне придется возвращать временные переменные, верно?" - если вы имеете в виду локальные переменные (вещи, объявленные в теле метода), то да. - CommonsWare 4 октября '14 в 20:46

Я знаю, что это скорее комментарий, чем ответ, но у меня нет репутации, чтобы комментировать, и я подумал, что это может быть полезно.

Другие вопросы по тегам