我们在混淆(Dexguard)Android应用程序中的Android 4.4.2(Nexus 7平板电脑)上使用SQLite(实际上是SQLCipher)。我们有ContentProviders来访问SQLite / SQLCipher数据库。其中一个ContentProviders从队列表返回消息。定期处理此队列 - 我们从队列中检索消息,然后使用cursor.moveToNext()迭代它们:
// Get cursor to iterate unsent messages
Cursor cursor = queueHelper.getMessages(Queue.STATUS_NEW);
try {
// Check if there are any unsent messages
if (cursor == null || cursor.getCount() == 0) {
// No queued messages to send
return;
}
// Send messages
while (cursor.moveToNext()) {
// Do stuff
}
}
这在我们自己的开发和测试期间可靠地工作,但是在现场我们看到偶然但重复的问题,在成功处理排队的消息之后,上面的cursor.moveToNext()调用抛出了IllegalStateException(注意) ,总是排0 col 0):
java.lang.IllegalStateException: get field slot from row 0 col 0 failed
at net.sqlcipher.CursorWindow.getLong_native(Native Method)
at net.sqlcipher.CursorWindow.getLong(:446)
at net.sqlcipher.AbstractWindowedCursor.getLong(:110)
at net.sqlcipher.AbstractCursor.moveToPosition(:199)
at net.sqlcipher.AbstractCursor.moveToNext(:228)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
在其他情况下,此行反而抛出CursorIndexOutOfBoundsException(请注意每次报告的实际索引/大小更改):
net.sqlcipher.CursorIndexOutOfBoundsException: Index 98 requested, with a size of 98
at net.sqlcipher.AbstractCursor.?(:556)
at net.sqlcipher.AbstractWindowedCursor.?(:222)
at net.sqlcipher.AbstractWindowedCursor.getLong(:101)
at net.sqlcipher.AbstractCursor.moveToPosition(:199)
at net.sqlcipher.AbstractCursor.moveToNext(:228)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
我们还没有能够重现任何一个问题,只有日志文件才能继续。这些日志表明成功处理行后出现问题。在此异常之后,该过程重新启动并继续进行而不会出现问题。我们无法理解为什么moveToNext会抛出异常 - 例如如果它在1-10行上工作,为什么要移到第11行会抛出异常? Cursor.moveToNext的文档说:
Move the cursor to the next row.
This method will return false if the cursor is already past the last entry in the result set.
因此它应该成功移动到next(并返回true)或失败(并返回false),而不是抛出这些奇怪的异常。
这听起来像是我们代码中的一个问题,还是一个SQLite问题,一个SQLCipher问题,或者与我们的混淆过程有关,或者是Dexguard,还是我们如何使用它?有什么建议吗?