删除项目后,CursorAdapter崩溃

时间:2016-07-12 15:52:22

标签: android cursor android-adapter

从数据库表中删除数据后,我的代码崩溃了。 我正在使用带有CursorWrapper的CursorAdapter。

场景是:

  1. CursorAdapter从游标加载器接收包装的游标
  2. 从ContentProvider中删除所有项目(通知notifyChange)
  3. 这是删除后的堆栈跟踪:

    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);
            }
        });
    }
    

    }

1 个答案:

答案 0 :(得分:0)

发现问题。我使用了错误的CursorAdapter构造函数。 这是正确的:

public EventsAdapter(Context context) {
        super(context, null, 0);

    }