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:一般来说,是的。当你查询某个第三方
内容提供商时尤其如此,因为有更多的事情可能出错(例如,应用程序崩溃)。这听起来像是个问题。你知道我能不能在期满后重新颁发赏金然后再颁发吗?