SQLiteBlobTooBigException: 行过长无法适应CursorWindow,所需位置为0,总行数为1。

28

我只在安卓9中遇到了以下异常,在重新安装后,一切都看起来正常。

异常:

android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1...

代码:

Cursor cursor = database.query(......);
    if(cursor == null || cursor.getCount() < 0) { //Here is the error
        Log.d("Error", "count : null");
        return "";
    }

编辑:

java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:354)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)

Caused by: android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1
at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method)
at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:859)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:836)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:149)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:137)

提前感谢大家


你能否编辑你的问题,展示完整的堆栈跟踪信息,而不仅仅是单独的一行信息呢?添加查询可能也会很有用。 - MikeT
我已经编辑了我的回答,请检查一下,@MikeT - Bikash Sahani
你找到解决方案了吗?我也遇到了@Bikash Sahani相同的异常。 - Nirmal Prajapat
每当有人在不卸载我的应用程序并继续使用它的情况下升级到Oreo时,就会出现这种情况,因此在那时我会删除表并重新创建它。 - Bikash Sahani
你解决了吗???这个问题我只在安卓9的Pocof1设备上遇到。在第一次安装后升级到Pie版本后,我就遇到了这个错误。重新安装后,一切都正常了。 - Aabauser
有没有解决方案? - gencaysahinn
4个回答

21

这个对我有用,你必须将其放在你的主活动上。

try {
    Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
    field.setAccessible(true);
    field.set(null, 100 * 1024 * 1024); //the 100MB is the new size
    } catch (Exception e) {
       e.printStackTrace();
    }

这绝对解决了问题,所以谢谢你和+1。快速跟进问题,有人知道这是否会触发任何级联的外部运行时异常吗?例如,如果用户设备上的可用空间小于100mb,是否会抛出异常?还是在RAM中正常工作? - PGMacDesign

4
请尝试使用API 28及以上的新构造方法。也许您应该为CursorWindow设置一个有限的windowSizeBytes,并尝试捕获异常。
相关的cts代码(https://android.googlesource.com/platform/cts/+/master/tests/tests/database/src/android/database/sqlite/cts/SQLiteCursorTest.java) :
    public void testRowTooBig() {
        mDatabase.execSQL("CREATE TABLE Tst (Txt BLOB NOT NULL);");
        byte[] testArr = new byte[10000];
        Arrays.fill(testArr, (byte) 1);
        for (int i = 0; i < 10; i++) {
            mDatabase.execSQL("INSERT INTO Tst VALUES (?)", new Object[]{testArr});
        }
        // Now reduce window size, so that no rows can fit
        Cursor cursor = mDatabase.rawQuery("SELECT * FROM TST", null);
        CursorWindow cw = new CursorWindow("test", 5000);
        AbstractWindowedCursor ac = (AbstractWindowedCursor) cursor;
        ac.setWindow(cw);
        try {
            ac.moveToNext();
            fail("Exception is expected when row exceeds CursorWindow size");
        } catch (SQLiteBlobTooBigException expected) {
        }
    }

其他:

自从最初的回答发表以来,我们在Android P开发者预览版中添加了新的API,以改善上述行为。现在平台允许应用程序禁用窗口三分之一启发式和配置CursorWindow大小。

参考链接: https://medium.com/androiddevelopers/large-database-queries-on-android-cb043ae626e8


0
尝试缩放位图:

Bitmap.createScaledBitmap

0

我发现了如何使用length()和substr()方法来请求只有1MB的数据(因为CursorWindow的最大容量是2MB),也许这会帮助你。另外,你可以使用context.getContentResolver().query()方法,并且只选择包含_id列的数据,这样就不会加载其他列相关的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接