从游标检索数据时出现异常:(请求了索引-1,大小为2)



嘿,我在Android Studio中从Cursor访问数据时遇到问题。我在数据库中有两个表事件消息。因此,事件表中的每个事件在消息表中可能有多条消息。事件及其消息共享一个公共的event_id。我正在使用LoaderCallbacksContentProvider获取游标。在ContentProviderquery方法中,我使用rawQuery来INNER JOIN这两个表。

在本例中,我查询一个事件,该事件与消息表中的两条消息共享其event_id。在ContentProvider中,执行了带有INNER JOIN的rawQuery((方法。在这种状态下,我可以在调试器中看到Cursor中的变量mCount是-1。我不知道这意味着什么,但无论如何,回到onLoadFinish((方法中,Cursor现在包含一个变量mCursor,这个变量再次包含一个为2的变量mCount。这是有道理的,因为查询应该返回一个有两行的Cursor,并且有两条消息。但现在我尝试使用getString((方法获取字符串,并抛出CursorIndexOutOfBoundsException:Index-1请求,大小为2。我真的不明白这意味着什么。我在Cursor文档中找不到任何提示,当mCount为-1时,这意味着什么。此外,在onLoadFinished方法中,变量mEditTable为null。在其他查询中,如果我不加入任何内容,它总是包含一个表。

我确信问题出在INNER JOIN上,因为如果我只在ContentProvider.query方法中使用一个查询方法,一切都会很好。但我不知道我应该做些什么。我希望你能帮我。我知道,如果没有与事件相关的消息,则此查询将返回mCount=0的空游标,然后再次抛出异常。但本例并非如此。

EventProvider类:

public class EventProvider extends ContentProvider {
private static final String LOG_TAG = EventProvider.class.getSimpleName();

private static final int EVENTS = 100;
private static final int EVENT_ID = 101;
private static final int EVENT_MESSAGE_ID = 102;
private static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private EventDbHelper mEventDbHelper;
static {
sUriMatcher.addURI(EventContract.CONTENT_AUTHORITY, EventContract.PATH_EVENTS, EVENTS);
sUriMatcher.addURI(EventContract.CONTENT_AUTHORITY, EventContract.PATH_EVENTS + "/#", EVENT_ID);
sUriMatcher.addURI(EventContract.CONTENT_AUTHORITY, EventContract.PATH_EVENT_AND_ITS_MESSAGES + "/#", EVENT_MESSAGE_ID);
}

@Override
public boolean onCreate() {
mEventDbHelper = new EventDbHelper(getContext());
return true;
}

@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
SQLiteDatabase database = mEventDbHelper.getReadableDatabase();
Cursor retCursor;
final int match = sUriMatcher.match(uri);
switch (match) {
case EVENTS:
retCursor = database.query(EventEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
break;
case EVENT_ID:
selection = EventEntry.COLUMN_EVENT_ID + "=?";
selectionArgs = new String[] {String.valueOf(ContentUris.parseId(uri))};
retCursor = database.query(EventEntry.TABLE_NAME, projection,selection, selectionArgs, null, null, sortOrder);
break;
case EVENT_MESSAGE_ID:
selection = MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_EVENT_ID + "=?";
selectionArgs = new String[] {String.valueOf(ContentUris.parseId(uri))};
StringBuilder sqlQuery = new StringBuilder();
sqlQuery.append("SELECT ");
if(projection != null && projection.length > 0) {
for(String s: projection) {
sqlQuery.append(s).append(", ");
}
}
sqlQuery.replace(sqlQuery.length()-2, sqlQuery.length(), " FROM ").append(MessageEntry.TABLE_NAME);
sqlQuery.append(" INNER JOIN ").append(EventEntry.TABLE_NAME).append(" ON ");
sqlQuery.append(EventEntry.TABLE_NAME).append(".").append(EventEntry.COLUMN_EVENT_ID).append("=");
sqlQuery.append(MessageEntry.TABLE_NAME).append(".").append(MessageEntry.COLUMN_EVENT_ID);
sqlQuery.append(" WHERE ").append(selection).append(" ORDER BY ").append(sortOrder).append(";");
Log.v(LOG_TAG, "SQL command for: " + uri.toString());
Log.v(LOG_TAG, sqlQuery.toString());
retCursor = database.rawQuery(sqlQuery.toString(), selectionArgs);
break;
default:
throw new IllegalArgumentException("Cannot query unknown URI: " + uri);
}
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}

事件活动:

@NonNull
@Override
public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) {
String[] projection = {
MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_EVENT_ID,
MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_SENDER,
MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_DATE,
MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_MESSAGE,
EventEntry.TABLE_NAME + "." + EventEntry._ID,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_NAME,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_DATE,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_DATE_ADDENDUM,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_CONTACT,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_STATUS,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_PICTURE_NAME,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_DESCRIPTION,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_STREET,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_HOUSE_NUMBER,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_POST_CODE,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_CITY,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_EMAIL,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_LOCATION,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_SIGNED_UP
};
String sortOrder = MessageEntry.COLUMN_DATE + " DESC";
return new CursorLoader(this, mCurrentEventUri, projection, null, null, sortOrder);
}

@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) {
int indexName = cursor.getColumnIndex(EventEntry.COLUMN_NAME);
int indexImage = cursor.getColumnIndex(EventEntry.COLUMN_PICTURE_NAME);
String imageName = cursor.getString(indexImage); //Here the Exception is thrown
mEventName.setText(cursor.getString(indexName));

mEventAdapter.swapCursor(cursor);
}

如果你需要其他东西,我会上传。谢谢

CursorIndexOutOfBoundsException:请求索引-1,大小为2

-1带光标通常是两个问题中的一个:-

  1. 传递给getColumnIndex的列名不是输出中的列名
  2. 光标在"0"的位置处的开始处;在第一行"之前;,就像返回Cursor时的情况一样

我怀疑您的问题是由2引起的,因为我相信消息指示了列的行。

2如果移动????(例如moveToFirst、moveToNext(方法未执行(我在您的代码中看不到任何此类移动(或未检查结果(移动方法返回true或false以指示是否可以满足移动请求(。

  • 请参阅(可能是moveToFirst(
    • https://developer.android.com/reference/android/database/Cursor#move(int(
    • https://developer.android.com/reference/android/database/Cursor#moveToFirst((
    • https://developer.android.com/reference/android/database/Cursor#moveToLast((
    • https://developer.android.com/reference/android/database/Cursor#moveToNext((
    • https://developer.android.com/reference/android/database/Cursor#moveToPosition(int(
    • https://developer.android.com/reference/android/database/Cursor#moveToPrevious((

修复方法是将光标移动到一行,检查移动是否真的成功,然后提取数据。

例如

String imageName = "No Image"
if (cursor.moveToFirst() && indexImage > -1) {    
imageName = cursor.getString(indexImage); //Here the Exception is thrown
}
  • 上面的&& indexImage > -1也会排除Cursor中不存在列名的情况

最新更新