什么可能导致这个SQLite CursorWindowAllocationException?

时间:2014-10-04 20:32:01

标签: android sqlite android-activity android-sqlite

我的Google Play开发者控制台报告了我的Android应用程序首次崩溃。看起来SQLite无法为光标分配内存,但我以前从未见过它并且无法重现它。有任何想法吗?

谷歌报道的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 个答案:

答案 0 :(得分:7)

实际上是OutOfMemoryError。引用the comments for that exception class

  

当无法分配CursorWindow时抛出此异常,很可能是因为内存不可用。

错误消息显示您有530个打开的Cursor个对象,这可能是您问题的一部分。例如,您在Cursor方法中泄漏getCourse()。确保在完成后立即关闭Cursor

如果这没有帮助,您需要将其视为OutOfMemoryError,并确定您在哪里浪费堆空间,可能是using tools like MAT

答案 1 :(得分:1)

游标需要关闭:

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

答案 2 :(得分:1)

如果您不想使用多个局部变量进行返回,则可以返回Cursor对象,然后从调用方法中将其关闭。

这是对#34;的响应。嗯。有时我使用return cursor.getString(0)。我想我不能在返回后关闭光标,也不能在关闭后使用它。我必须返回临时变量,对吧? - NSouth Oct 4&#39; 14 at 20:44:&amp;

@NSouth:&#34;我必须返回临时变量,对吗?&#34; - 如果你的意思是局部变量(在方法体中声明的东西),那么是的。 - CommonsWare 10月4日和14日在20:46

我知道这更像是一个评论,然后是答案,但我没有评论的声誉点,并认为这可能会有所帮助。