从数据库表中删除数据后,我的代码崩溃了。 我正在使用带有CursorWrapper的CursorAdapter。
场景是:
这是删除后的堆栈跟踪:
java.lang.IllegalStateException: couldn't move cursor to position 0
at android.widget.CursorAdapter.getView(CursorAdapter.java:281)
at android.widget.AbsListView.obtainView(AbsListView.java:2929)
at android.widget.ListView.makeAndAddView(ListView.java:1945)
at android.widget.ListView.fillSpecific(ListView.java:1379)
at android.widget.ListView.layoutChildren(ListView.java:1712)
at android.widget.AbsListView.onLayout(AbsListView.java:2723)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:344)
at android.widget.FrameLayout.onLayout(FrameLayout.java:281)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:344)
at android.widget.FrameLayout.onLayout(FrameLayout.java:281)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1742)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1187)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:344)
at android.widget.FrameLayout.onLayout(FrameLayout.java:281)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1742)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:344)
at android.widget.FrameLayout.onLayout(FrameLayout.java:281)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1742)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:344)
at android.widget.FrameLayout.onLayout(FrameLayout.java:281)
at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:3193)
at android.view.View.layout(View.java:17938)
at android.view.ViewGroup.layout(ViewGroup.java:5812)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2666)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2367)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1437)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7397)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920)
at android.view.Choreographer.doCallbacks(Choreographer.java:695)
at android.view.Choreographer.doFrame(Choreographer.java:631)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
游标包装器取自here。
/**
*包装光标并允许其位置被过滤掉,重复或重新排序。常见的创作方式 * FilteredCursor对象由{@link FilteredCursorFactory}提供。 * *请注意,如果源Cursor超过{@link android.database.CursorWindow}的大小,则FilteredCursor *由于频繁的CursorWindow缓存未命中,可能最终会导致性能极差。在那些情况下它是 *建议源Cursor包含较少的数据。 * * @author Jacob Whitaker艾布拉姆斯 * / 公共类FilteredCursor扩展了CursorWrapper {
// Globally map master Cursor to FilteredCursors, when all FilteredCursors are closed go ahead and close the master
// This would need to go into a singleton if other classes similar to FilteredCursor exist
private static final Map<Cursor, Set<FilteredCursor>> sMasterCursorMap =
Collections.synchronizedMap(new WeakHashMap<Cursor, Set<FilteredCursor>>());
private int[] mFilterMap;
private int mPos = -1;
private final Cursor mCursor;
private boolean mClosed;
/**
* Create a FilteredCursor that appears identical to its wrapped Cursor.
*/
public static FilteredCursor createUsingIdentityFilter(Cursor cursor) {
if (cursor == null) {
return null;
}
return new FilteredCursor(cursor);
}
/**
* Create a new FilteredCursor using the given filter. The filter specifies where rows of the given Cursor should
* appear in the FilteredCursor. For example if filter = { 5, 9 } then the FilteredCursor will have two rows, the
* first row maps to row 5 in the source Cursor and the second row maps to row 9 in the source cursor. Returns null
* if the provided cursor is null. A value of -1 in the filter is treated as an empty row in the Cursor with no data,
* see {@link FilteredCursor#isPositionEmpty()}.
*/
public static FilteredCursor createUsingFilter(Cursor cursor, int[] filter) {
if (cursor == null) {
return null;
}
if (filter == null) {
throw new NullPointerException();
}
return new FilteredCursor(cursor, filter);
}
private FilteredCursor(Cursor cursor) {
this(cursor, null);
resetToIdentityFilter();
}
private FilteredCursor(Cursor cursor, int[] filterMap) {
super(cursor);
mCursor = cursor;
mFilterMap = filterMap;
attachToMasterCursor();
}
public int[] getFilterMap() {
return mFilterMap;
}
/**
* Reset the filter so it appears identical to its wrapped Cursor.
*/
public FilteredCursor resetToIdentityFilter() {
int count = mCursor.getCount();
int[] filterMap = new int[count];
for (int i = 0; i < count; i++) {
filterMap[i] = i;
}
mFilterMap = filterMap;
mPos = -1;
return this;
}
/**
* Returns true if the FilteredCursor appears identical to its wrapped Cursor.
*/
public boolean isIdentityFilter() {
int count = mCursor.getCount();
if (mFilterMap.length != count) {
return false;
}
for (int i = 0; i < count; i++) {
if (mFilterMap[i] != i) {
return false;
}
}
return true;
}
/**
* Rearrange the filter. The new arrangement is based on the current filter arrangement, not on the source Cursor's
* arrangement.
*/
public FilteredCursor refilter(int[] newArrangement) {
final int newMapSize = newArrangement.length;
int[] newMap = new int[newMapSize];
for (int i = 0; i < newMapSize; i++) {
newMap[i] = mFilterMap[newArrangement[i]];
}
mFilterMap = newMap;
mPos = -1;
return this;
}
/**
* True if the current cursor position has no data. Attempting to access data in an empty row with any of the getters
* will throw {@link UnsupportedOperationException}.
*/
public boolean isPositionEmpty() {
return mFilterMap[mPos] == -1;
}
private void throwIfEmptyRow() {
if (isPositionEmpty()) {
throw new UnsupportedOperationException("Cannot access data in an empty row");
}
}
public void swapItems(int itemOne, int itemTwo) {
int temp = mFilterMap[itemOne];
mFilterMap[itemOne] = mFilterMap[itemTwo];
mFilterMap[itemTwo] = temp;
}
@Override
public int getCount() {
return mFilterMap.length;
}
@Override
public int getPosition() {
return mPos;
}
@Override
public boolean moveToPosition(int position) {
// Make sure position isn't past the end of the cursor
final int count = getCount();
if (position >= count) {
mPos = count;
return false;
}
// Make sure position isn't before the beginning of the cursor
if (position < 0) {
mPos = -1;
return false;
}
final int realPosition = mFilterMap[position];
// When moving to an empty position, just pretend we did it
boolean moved = realPosition == -1 ? true : super.moveToPosition(realPosition);
if (moved) {
mPos = position;
} else {
mPos = -1;
}
return moved;
}
@Override
public final boolean move(int offset) {
return moveToPosition(mPos + offset);
}
@Override
public final boolean moveToFirst() {
return moveToPosition(0);
}
@Override
public final boolean moveToLast() {
return moveToPosition(getCount() - 1);
}
@Override
public final boolean moveToNext() {
return moveToPosition(mPos + 1);
}
@Override
public final boolean moveToPrevious() {
return moveToPosition(mPos - 1);
}
@Override
public final boolean isFirst() {
return mPos == 0 && getCount() != 0;
}
@Override
public final boolean isLast() {
int count = getCount();
return mPos == (count - 1) && count != 0;
}
@Override
public final boolean isBeforeFirst() {
if (getCount() == 0) {
return true;
}
return mPos == -1;
}
@Override
public final boolean isAfterLast() {
if (getCount() == 0) {
return true;
}
return mPos == getCount();
}
@Override
public boolean isNull(int columnIndex) {
throwIfEmptyRow();
return mCursor.isNull(columnIndex);
}
@Override
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
throwIfEmptyRow();
mCursor.copyStringToBuffer(columnIndex, buffer);
}
@Override
public byte[] getBlob(int columnIndex) {
throwIfEmptyRow();
return mCursor.getBlob(columnIndex);
}
@Override
public double getDouble(int columnIndex) {
throwIfEmptyRow();
return mCursor.getDouble(columnIndex);
}
@Override
public float getFloat(int columnIndex) {
throwIfEmptyRow();
return mCursor.getFloat(columnIndex);
}
@Override
public int getInt(int columnIndex) {
throwIfEmptyRow();
return mCursor.getInt(columnIndex);
}
@Override
public long getLong(int columnIndex) {
throwIfEmptyRow();
return mCursor.getLong(columnIndex);
}
@Override
public short getShort(int columnIndex) {
throwIfEmptyRow();
return mCursor.getShort(columnIndex);
}
@Override
public String getString(int columnIndex) {
throwIfEmptyRow();
return mCursor.getString(columnIndex);
}
@Override
public boolean isClosed() {
return mClosed || getMasterCursor().isClosed();
}
@Override
public void close() {
// Mark this Cursor as closed
mClosed = true;
// Only close the wrapped cursor if no other FilteredCursors are referencing the master cursor
Cursor masterCursor = getMasterCursor();
Set<FilteredCursor> linkedFilteredCursorSet = sMasterCursorMap.get(masterCursor);
if (linkedFilteredCursorSet == null) {
super.close(); // Shouldn't ever happen?
} else {
linkedFilteredCursorSet.remove(this);
if (linkedFilteredCursorSet.isEmpty()) {
super.close();
}
}
if (masterCursor.isClosed()) {
sMasterCursorMap.remove(masterCursor);
}
}
private void attachToMasterCursor() {
Cursor masterCursor = getMasterCursor();
Set<FilteredCursor> filteredCursorSet = sMasterCursorMap.get(masterCursor);
if (filteredCursorSet == null) {
filteredCursorSet = Collections.synchronizedSet(new HashSet<FilteredCursor>());
sMasterCursorMap.put(masterCursor, filteredCursorSet);
}
filteredCursorSet.add(this);
}
/** Returns the first non-CursorWrapper instance contained within this object. */
public Cursor getMasterCursor() {
Cursor cursor = mCursor;
while (cursor instanceof CursorWrapper) {
cursor = ((CursorWrapper) cursor).getWrappedCursor();
}
return cursor;
}
/** Returns the first FilteredCursor wrapped by the provided cursor or null if no FilteredCursor is found. */
public static FilteredCursor unwrapFilteredCursor(Cursor cursor) {
while (cursor instanceof CursorWrapper) {
if (cursor instanceof FilteredCursor) {
return (FilteredCursor)cursor;
} else {
cursor = ((CursorWrapper) cursor).getWrappedCursor();
}
}
return null;
}
内容提供商删除
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = getWritableDb();
int result = 0;
switch (sUriMatcher.match(uri)) {
case EVENT_LIST:
result = db.delete(EventDataContract.TABLE_NAME, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
return result;
}
光标加载器
public class EventsCurorLoader extends CursorLoader {
public EventsCurorLoader(Context context) {
super(context, EventData.CONTENT_URI, EventData.PROJECTION_ALL, null, null, EventDataContract.EventDataColumns.TIMESTAMP + " DESC");
}
@Override
protected Cursor onLoadInBackground() {
Cursor c = super.onLoadInBackground();
// Filter the cursor using user preferences
final Set<String> filter = GeneralSettings.getInstance(getContext()).getEventsFilter();
return FilteredCursorFactory.createUsingSelector(c, new FilteredCursorFactory.Selector() {
@Override
public boolean select(Cursor cursor) {
String type = cursor.getString(EventData.TYPE_COLUMN_ID);
return filter.contains(type);
}
});
}
}
答案 0 :(得分:0)
发现问题。我使用了错误的CursorAdapter构造函数。 这是正确的:
public EventsAdapter(Context context) {
super(context, null, 0);
}