Java Cursor.moveToNext错误
我偶尔会看到这方面的事故报告:Java Cursor.moveToNext错误,java,android,sqlite,android-contentprovider,android-cursor,Java,Android,Sqlite,Android Contentprovider,Android Cursor,我偶尔会看到这方面的事故报告: Fatal Exception: java.lang.IllegalStateException: Couldn't read row 1127, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. at android.database.CursorWindow.nativeGetLong(CursorW
Fatal Exception: java.lang.IllegalStateException: Couldn't read row 1127, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetLong(CursorWindow.java)
at android.database.CursorWindow.getLong(CursorWindow.java:511)
at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:220)
at android.database.AbstractCursor.moveToNext(AbstractCursor.java:245)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
at com.anthonymandra.util.ImageUtils.cleanDatabase(SourceFile:381)
显然,moveToNext
在中间循环中失败(注意第1127行)。循环将删除表示无法再找到的文件的条目
final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
try( Cursor cursor = c.getContentResolver().query(Meta.CONTENT_URI, null, null, null, null))
{
if (cursor == null)
return;
final int uriColumn = cursor.getColumnIndex(Meta.URI);
final int idColumn = cursor.getColumnIndex(BaseColumns._ID);
while (cursor.moveToNext())
{
String uriString = cursor.getString(uriColumn);
if (uriString == null) // we've got some bogus data, just remove
{
operations.add(ContentProviderOperation.newDelete(
Uri.withAppendedPath(Meta.CONTENT_URI, cursor.getString(idColumn))).build());
continue;
}
Uri uri = Uri.parse(uriString);
UsefulDocumentFile file = UsefulDocumentFile.fromUri(c, uri);
if (!file.exists())
{
operations.add(ContentProviderOperation.newDelete(Meta.CONTENT_URI)
.withSelection(getWhere(), new String[]{uriString}).build());
}
}
}
c.getContentResolver().applyBatch(Meta.AUTHORITY, operations);
final ArrayList operations=new ArrayList();
try(Cursor Cursor=c.getContentResolver().query(Meta.CONTENT_URI,null,null,null))
{
if(游标==null)
返回;
final int-uriColumn=cursor.getColumnIndex(Meta.URI);
final int ID column=cursor.getColumnIndex(BaseColumns.\u ID);
while(cursor.moveToNext())
{
String uriString=cursor.getString(uriColumn);
如果(uriString==null)//我们有一些虚假数据,只需删除
{
添加(ContentProviderOperation.newDelete(
withAppendedPath(Meta.CONTENT_Uri,cursor.getString(idColumn))).build();
继续;
}
Uri=Uri.parse(uriString);
UsefulDocumentFile=UsefulDocumentFile.fromUri(c,uri);
如果(!file.exists())
{
add(ContentProviderOperation.newDelete(Meta.CONTENT\u URI)
.withSelection(getWhere(),新字符串[]{uriString}).build());
}
}
}
c、 getContentResolver().applyBatch(Meta.AUTHORITY,operations);
你知道游标怎么会在循环中间失败吗?可能是因为你是数据库中的srote文件,这就是为什么你会得到
java.lang.IllegalStateException
UsefulDocumentFile file = UsefulDocumentFile.fromUri(c, uri);
Android SQLite在游标窗口中返回最大大小为2MB的行,如
。如果您的行超过此限制,则会出现此错误
将文件存储在文件系统中,并将路径存储在数据库中。您似乎在进行一个相当大的查询:至少1127行,以及所有可能的列(尽管您只使用了其中的两行)。并且,在您使用该
光标的过程中,您正在对内容提供者执行磁盘I/O和/或IPC操作,假设有用的文档文件
与Android的文档文件
相关
正如Prakash所指出的,您返回的光标
可能只包含信息的一个子集。一旦您尝试前进超过该点,光标
需要返回到数据源并获得下一个结果窗口。如果在这项工作进行期间数据发生了实质性的变化(例如,现在的行数不到1127行),我可以看到您会遇到这种问题
我建议你:
- 将获取的列约束回所需的子集,然后
- 在循环过程中避免I/O(例如,旋转
光标
以建立数组列表
或其他,关闭光标
,然后在列表上迭代)
这是您的完整日志?您是否建议我创建一个UsefulDocumentFile
数组(是的,这是一个DocumentFile
,有很多改进)。这些操作已经放置在数组中,然后进行批处理。UsefulDocumentFile
创建将通过SAF在不同的数据库上运行。简单I/O或IPC是否会导致问题?不过我真的应该使用投影。在早期的创建中忽略了投影,这个习惯就一直存在。@Anthony:“你是在建议我创建一个有用的DocumentFile数组吗?”——这可能有效。我不确定DocumentFile
是否在fromUri()
中进行I/O操作。如果是这样的话,那么我将保留Uri
,等待创建DocumentFile
实例,直到您使用光标完成。“简单的I/O或IPC会导致问题吗?”--嗯,它会减慢速度,需要您将光标保持更长时间的打开状态,这增加了windows出现问题的可能性。对于小的查询,你肯定会在一个窗口内,这不是什么大问题。我在一些地方会出现类似这样的小问题。当我看到它出现在堆栈跟踪中时,我理解了CursorWindow
的思想,但我没有理解我正在进行的大型查询的严重性和窗口的移动。那么,你会说,当你知道有可能出现一个大型查询时,试着快速摆脱光标,然后拉取需要的数据,然后在关闭后进行处理吗?@Anthony:一般来说,是的。当你查询某个第三方内容提供商时尤其如此,因为有更多的事情可能出错(例如,应用程序崩溃)。这听起来像是个问题。你知道我能不能在期满后重新颁发赏金然后再颁发吗?