使用CursorRecyclerViewAdapter时,notifyChange不更新UI

时间:2015-06-03 15:30:05

标签: android android-contentprovider android-adapter android-recyclerview

Android不提供要与recyclerView一起使用的CursorAdapter。

我尝试过使用此处的CursorRecyclerViewAdapter: https://gist.github.com/skyfishjy/443b7448f59be978bc59

当我从ContentProvider调用notifyChange时, 观察者没有被调用。

~SNIP my Fragment / Controller ....

 //adapter
        mAdapter = new CursorRecyclerViewAdapter(getActivity(), null,true) {
            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, Cursor cursor) {
            ((WidgetAdapter.ViewHolder)viewHolder).setTitle(cursor.getString(4)  + "  id: " + cursor.getInt(0) + " order: " + cursor.getInt(15));
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            Context context = viewGroup.getContext();
            View parent = LayoutInflater.from(context).inflate(R.layout.ned_apps_order_item, viewGroup, false);
            return WidgetAdapter.ViewHolder.newInstance(parent);
        }

    };

    mRecyclerView.setAdapter(mAdapter);

~SNIP - Loader CallBacks

@Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        String parent_id = bundle == null ? "0" : "" + bundle.getInt(PARENT_ID);
        String PARENT_SELECTION = PARENT_ID + "= ?";

        return new CursorLoader(getActivity(), Schema.CONTENT_URI,null,
                PARENT_SELECTION,new String[] {parent_id}, "_order ASC");
    }

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    mAdapter.swapCursor(cursor);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    mAdapter.swapCursor(null);
}

~SNIP

~SNIP~ my Provider.....
 @Override
    public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {

        String modifiedSelection = selection;

        switch (uriMatcher.match(uri)) {
            case WIDGET_ID: {
                modifiedSelection += " = " + uri.getLastPathSegment();
                System.out.println(">>"+modifiedSelection);
            }
        }

        int updateCount = 0;
        updateCount = database.update(Schema.Table.TABLE_NAME,contentValues,modifiedSelection,null);



        if (updateCount == 1) {
            getContext().getContentResolver().notifyChange(uri,null);
        }

        return updateCount;
    }
~SNIP~

~SNIP - skyfishjy

import android.content.Context;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.support.v7.widget.RecyclerView;

/**
 * Created by skyfishjy on 10/31/14.
 */

public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {

    private Context mContext;

    private Cursor mCursor;

    private boolean mDataValid;

    private int mRowIdColumn;

    private DataSetObserver mDataSetObserver;

    public CursorRecyclerViewAdapter(Context context, Cursor cursor,boolean hasStableIds) {
        mContext = context;
        mCursor = cursor;
        mDataValid = cursor != null;
        mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1;
        mDataSetObserver = new NotifyingDataSetObserver();
        if (mCursor != null) {
            mCursor.registerDataSetObserver(mDataSetObserver);
        }
        super.setHasStableIds(hasStableIds);
    }

    public Cursor getCursor() {
        return mCursor;
    }


    @Override
    public int getItemCount() {
        if (mDataValid && mCursor != null) {
            return mCursor.getCount();
        }
        return 0;
    }

    @Override
    public long getItemId(int position) {
        if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) {
            return mCursor.getLong(mRowIdColumn);
        }
        return 0;
    }

    @Override
    public void setHasStableIds(boolean hasStableIds) {
        super.setHasStableIds(true);
    }

    public abstract void onBindViewHolder(VH viewHolder, Cursor cursor);

    @Override
    public void onBindViewHolder(VH viewHolder, int position) {
        if (!mDataValid) {
            throw new IllegalStateException("this should only be called when the cursor is valid");
        }
        if (!mCursor.moveToPosition(position)) {
            throw new IllegalStateException("couldn't move cursor to position " + position);
        }
        onBindViewHolder(viewHolder, mCursor);
    }

    /**
     * Change the underlying cursor to a new cursor. If there is an existing cursor it will be
     * closed.
     */
    public void changeCursor(Cursor cursor) {
        Cursor old = swapCursor(cursor);
        if (old != null) {
            old.close();
        }
    }

    /**
     * Swap in a new Cursor, returning the old Cursor.  Unlike
     * {@link #changeCursor(Cursor)}, the returned old Cursor is <em>not</em>
     * closed.
     */
    public Cursor swapCursor(Cursor newCursor) {
        if (newCursor == mCursor) {
            return null;
        }
        final Cursor oldCursor = mCursor;
        if (oldCursor != null && mDataSetObserver != null) {
            oldCursor.unregisterDataSetObserver(mDataSetObserver);
        }
        mCursor = newCursor;
        if (mCursor != null) {
            if (mDataSetObserver != null) {
                mCursor.registerDataSetObserver(mDataSetObserver);
            }
            mRowIdColumn = newCursor.getColumnIndexOrThrow("_id");
            mDataValid = true;
            notifyDataSetChanged();
        } else {
            mRowIdColumn = -1;
            mDataValid = false;
            notifyDataSetChanged();
            //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
        }
        return oldCursor;
    }

    public int getPositionForId(long id) {

        mCursor.moveToFirst();

        while (mCursor.moveToNext()) {
            if (mCursor.getInt(0) == id) {
                return mCursor.getInt(15);
            }
        }

        return -1;
    }


    private class NotifyingDataSetObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            mDataValid = true;
            notifyDataSetChanged();
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            mDataValid = false;
            notifyDataSetChanged();
            //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
        }
    }
}

1 个答案:

答案 0 :(得分:2)

我发现了问题,它没有在我的代码中列出 问题

@Override
    public Cursor query(final Uri uri, final String[] projection,
                        final String selection, final String[] selectionArgs,
                        final String sortOrder) {

        Log.d(TAG, "query()" + uri.toString());

        String modifiedSelection = selection;

        switch (uriMatcher.match(uri)) {

            case WIDGET_ID: {
                modifiedSelection += SchemaTable.ID
                        + " = " + uri.getLastPathSegment();
                break;
            }

            case WIDGETS: {
                //return database.query(Schema.Table.TABLE_NAME, WidgetModel.getAllColumns(), selection, selectionArgs, null, null, sortOrder);
                break;
            }

            default: {
                //TODO log only when this is a debug build
                throw new IllegalArgumentException("Unknown URI: " + uri);
            }
        }

        return database.query(Schema.Table.TABLE_NAME,WidgetModel.getAllColumns(), modifiedSelection, selectionArgs, null, null, sortOrder); 
    }

这条线丢失了:

....setNotificationUri(getContext().getContentResolver(),uri);

然后使用以下代码替换return语句:

Cursor cursor = database.query(Schema.Table.TABLE_NAME, WidgetModel.getAllColumns(), modifiedSelection, selectionArgs, null, null, sortOrder);
            cursor.setNotificationUri(getContext().getContentResolver(),uri);
            return cursor;