android sqlite blob,更新了Blob后,Android sqlite无法读取

我想在SQLite数据库中存储一个图像(大小约为10MB)。 为此,我创建了一个数据库助手Dao。 一切正常,我可以创建多个记录并毫无问题地读取它们,甚至可以毫无问题地更新最新记录中的blob。

但是,如果我返回到较旧的记录并更新Blob,则无法再使用Blob加载此记录。

我有一个列表视图,其中显示了所有记录,为此,我使用了不返回Blob的选择。 该列表可以正常工作,但是当我单击列表中的一个项目时,我尝试使用blob加载记录,光标将返回0行。

public void save(Bill aBill) {

ContentValues values = new 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(true);

} else {

database.update(DatabaseHelper.BILL_TABLE, values, DatabaseHelper.BILL_ID_COLUMN +"=?", new String[]{String.valueOf(aBill.getId())});

}

}

// fails after updating the blob

public Bill get(long id) {

Cursor cursor = database.query(DatabaseHelper.BILL_TABLE,

new String[]{DatabaseHelper.BILL_ID_COLUMN, DatabaseHelper.BILL_NAME_COLUMN, DatabaseHelper.BILL_DUE_DATE_COLUMN, DatabaseHelper.BILL_IMAGE_COLUMN},"id = ?", new String[] {String.valueOf(id)}, null,

null, DatabaseHelper.BILL_DUE_DATE_COLUMN);

Bill bill = null;

while (cursor.moveToNext()) {

bill = new Bill();

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();

return bill;

}

//works fine after updating the blob

public List findAll() {

List bills = new ArrayList();

Cursor cursor = database.query(DatabaseHelper.BILL_TABLE,

new String[]{DatabaseHelper.BILL_ID_COLUMN, DatabaseHelper.BILL_NAME_COLUMN, DatabaseHelper.BILL_DUE_DATE_COLUMN}, null, null, null,

null, DatabaseHelper.BILL_DUE_DATE_COLUMN);

while (cursor.moveToNext()) {

Bill bill = new Bill();

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(bill);

}

cursor.close();

return bills;

}

这是例外:

java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.

at android.database.CursorWindow.nativeGetLong(Native Method)

at android.database.CursorWindow.getLong(CursorWindow.java:511)

at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75)

at net.rka.android.billreminder.BillDao.get(BillDao.java:106)

我怀疑连续更新Blob会以某种方式破坏数据库。

有人遇到过类似的问题吗? 如果是这样,您如何解决?

考虑到如何提出一个好的问题,您需要包括相关代码。

您是否在日志中有堆栈跟踪,如果有的话,添加它。图片有多大?仅当读入游标而不是在插入/更新列时才适用的限制是,如果有内存,CursorWindow可以容纳1或2m的数据大小(因此通常只能在BLOB中看到)

添加了堆栈跟踪。日志中没有先前的错误。正如我所说的那样,我可以添加具有相同大小图像的新记录而不会出现问题。我可以打开它们。我什至可以一遍又一遍更新最后一条记录,也可以加载它们。但是,当我更新以前的记录之一时,这些记录无法打开。光标不包含记录。

尝试在while (cursor.moveToNext()) { ....之前添加DatabaseUtils.dumpCursor(cursor);。输出将在日志中。另外,请尝试从查询中忽略图片,看看是否可行。

10Mb图像大小可能会导致问题。最多可以平均约10万,然后可以将图像存储在DB中。然后,更大的文件应该真正将图像存储为文件并将路径存储在DB中。

确定您可以在没有图像的情况下进行检索。建议不要尝试仅将图像的存储路径存储在DB中。

转储是一个很好的提示。它产生以下消息:W / CursorWindow:窗口已满:请求的分配3282011字节,可用空间2096677字节,窗口大小2097152字节窗口已满:请求的分配3282011字节,可用的空间2096677字节,窗口大小2097152字节

我真的不喜欢单独存储文件的想法,它增加了我的小示例应用程序的复杂性,必须具有额外的代码来确保db和文件系统同步。很烦,因为类似的东西可能是一个常见的用例。宁愿尝试其他方法,也不愿编码变通办法。

不只是一个普通的用例,而是一个通常不鼓励的用例(至少那是我对SO的理解)。其他选项可以极大地减小图像大小,例如每2M至少减小10-20,或者与C ++以及SQLIte3本机一起使用(如果这是正确的术语)来编写自己的图像。但是,也许有一些库/工具包对此有所规避。并不是说我看到过任何提及。

您的问题很可能是由于图像的大小和怪异,为了更好的用语,您可以存储大的BLOB而没有问题,但是由于Android的Cursor Window 2m的大小限制,您可能无法检索BLOB。有时,某些SQLiteDatabase / Cursor(在此情况下为Cursor getBlob()或它的基础方法)方法变得更加复杂,这些方法基本上隐藏了基础故障,以便提供通常更简单的开发经验。

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

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

while (cursor.moveToNext()) { ........

可能提供线索。

我可以想到3种选择:

与其将文件存储为BLOBS,不如将文件存储为磁盘上的文件并将路径存储在数据库中。

显着减小图像尺寸。

研究使用C ++和本机SQLIte3库将BLOBS检索到适当大小的容器中。

也许可能有些图书馆这样做。但是,我不记得有任何提及。

你可能感兴趣的:(android,sqlite,blob)