更新 blob 后,Android sqlite 无法读取

Posted

技术标签:

【中文标题】更新 blob 后,Android sqlite 无法读取【英文标题】:Android sqlite unable to read after updating a blob 【发布时间】:2018-11-11 02:07:11 【问题描述】:

我想在 SQLite 数据库中存储一个图像(大小约为 10MB)。为此,我创建了一个 DB 助手,一个 Dao。一切正常,我可以创建多条记录并毫无问题地读取它们,我什至可以毫无问题地更新最新记录中的 blob。 但是,如果我返回旧记录并更新 blob,我将无法再使用 blob 加载此记录。 我有一个显示所有记录的列表视图,为此我使用不返回 blob 的选择。此列表工作正常,但是当我单击列表中的某个项目时,我尝试使用 blob 加载记录,光标返回 0 行。

公共无效保存(比尔比尔) ContentValues 值 = 新 ContentValues(); values.put(DatabaseHelper.BILL_NAME_COLUMN, aBill.getName()); values.put(DatabaseHelper.BILL_DUE_DATE_COLUMN, getContentValue(aBill.getDueDate())); values.put(DatabaseHelper.BILL_IMAGE_COLUMN, aBill.getImage()); if (!aBill.isPersistent()) aBill.setId(database.insert(DatabaseHelper.BILL_TABLE, null, values)); abill.setpersistent(真实); 别的 database.update(DatabaseHelper.BILL_TABLE, values, DatabaseHelper.BILL_ID_COLUMN + "=?", new String[]String.valueOf(aBill.getId())); // 更新 blob 后失败 公共账单得到(长ID) 光标 cursor = database.query(DatabaseHelper.BILL_TABLE, 新字符串 [] DatabaseHelper.BILL_ID_COLUMN,DatabaseHelper.BILL_NAME_COLUMN,DatabaseHelper.BILL_DUE_DATE_COLUMN,DatabaseHelper.BILL_IMAGE_COLUMN,“id = ?”,新字符串 [] String.valueOf(id),空, 空,DatabaseHelper.BILL_DUE_DATE_COLUMN); 比尔比尔= null; while (cursor.moveToNext()) 比尔=新比尔(); Bill.Setpersistent(True); bill.setId(cursor.getLong(cursor.getColumnIndex(DatabaseHelper.BILL_ID_COLUMN))); bill.setName(cursor.getString(cursor.getColumnIndex(DatabaseHelper.BILL_NAME_COLUMN))); bill.setDueDate(getDate(cursor.getString(cursor.getColumnIndex(DatabaseHelper.BILL_DUE_DATE_COLUMN)))); bill.setImage(cursor.getBlob(cursor.getColumnIndex(DatabaseHelper.BILL_IMAGE_COLUMN))); cursor.close(); 返回账单; //更新blob后工作正常 公共列表pindall() 列出账单 = new ArrayList(); 光标 cursor = database.query(DatabaseHelper.BILL_TABLE, 新字符串 [] DatabaseHelper.BILL_ID_COLUMN,DatabaseHelper.BILL_NAME_COLUMN,DatabaseHelper.BILL_DUE_DATE_COLUMN,空,空,空, 空,DatabaseHelper.BILL_DUE_DATE_COLUMN); while (cursor.moveToNext()) 比尔比尔=新比尔(); Bill.Setpersistent(True); bill.setId(cursor.getLong(cursor.getColumnIndex(DatabaseHelper.BILL_ID_COLUMN))); bill.setName(cursor.getString(cursor.getColumnIndex(DatabaseHelper.BILL_NAME_COLUMN))); bill.setDueDate(getDate(cursor.getString(cursor.getColumnIndex(DatabaseHelper.BILL_DUE_DATE_COLUMN)))); Bills.add(比尔); cursor.close(); 退货;

这是一个例外:

java.lang.IllegalStateException:无法从 CursorWindow 读取第 0 行第 0 列。确保在从光标访问数据之前正确初始化光标。 在 android.database.CursorWindow.nativeGetLong(本机方法) 在 android.database.CursorWindow.getLong(CursorWindow.java:511) 在 android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75) 在 net.rka.android.billreminder.BillDao.get(BillDao.java:106)

我怀疑连续更新 blob 会以某种方式损坏数据库。 有没有人遇到过类似的问题?如果有,你是怎么解决的?

【问题讨论】:

你需要包含相关代码,考虑How do I ask a good question? 日志中是否有堆栈跟踪,如果有,请添加。图片有多大?作为仅在读入游标时适用的限制,而不是在插入/更新列时,如果内存服务,CursorWindow 可以容纳 1 或 2m 的数据大小(因此通常只看到 BLOB) 添加了堆栈跟踪。日志中没有以前的错误。正如我所说的,它工作正常,我可以毫无问题地添加具有相同大小图像的新记录。我可以打开它们。我什至可以一遍又一遍地更新最后一条记录并加载它们。但是当我更新以前的记录之一时,这些记录无法打开。光标不包含记录。 尝试在while (cursor.moveToNext()) .... 之前添加DatabaseUtils.dumpCursor(cursor);。输出将在日志中。还可以尝试从查询中省略图像,看看是否有效。 10Mb 图像大小很可能会导致问题。最多大约和平均大约 100k 然后可以将图像存储在数据库中。再大一点,你应该真正将图像存储为文件并将路径存储在数据库中。 【参考方案1】:

您的问题很可能是由于图像的大小和一个怪癖,为了更好的术语,您可以毫无问题地存储大型 BLOB,但由于 Android 的光标窗口的大小限制2m,您可能无法检索 BLOB。这有时会与一些 SQLiteDatabase/Cursor (在这种情况下为 Cursor getBlob() 或它的底层方法) 方法复杂化,这些方法基本上隐藏了底层故障,以提供通常更简单的开发体验。

如果您使用 SQLiteDatabase DatabaseUtils.dumpCursor 这可能会突出显示 SQLiteDatabase 查询便捷方法可能隐藏的问题。所以添加:-

DatabaseUtils.dumpCursor(cursor); //<<<< ADDED
while (cursor.moveToNext())  ........

可能会提供线索。

我能想到 3 个选项:-

    不是将文件存储为 BLOBS,而是将文件存储为磁盘上的文件并将路径存储在数据库中。 显着减小图像的大小。 研究使用 C++ 和本机 SQLIte3 库将 BLOBS 检索到适当大小的容器中。

也许有一些库可以做到这一点。但是,我不记得有人提到过。

【讨论】:

以上是关于更新 blob 后,Android sqlite 无法读取的主要内容,如果未能解决你的问题,请参考以下文章

从 Android sqlite 数据库中检索大 blob

不理解?为啥我们在“Android Sqlite”中需要 BLOB

Android - 添加到 SQLite 数据库后不会更新 ListView,除非重新启动应用程序

Android中的Sugar ORM:更新SQLite中保存的对象

Android 在保存到 SQLITE 时更改像素或图像大小

Blob Row 太大太适合 Android