如何在数据集更改时更新RecyclerView?

时间:2015-07-08 13:48:28

标签: android android-recyclerview android-adapter android-cursorloader activeandroid

我在Android应用程序中使用ActiveAndroid ORM和UltimateRecyclerView。我不知道如何使用这个流行的库在列表中显示数据。我知道,数据正确保存到数据库。使用以下方法,我得到一个光标到我想要显示的数据。

public Cursor eventsCursor() {
    // `Event` is an ActiveAndroid model class
    String query = new Select()
            .from(Event.class)
            .orderBy("time")
            .toSql();
    return ActiveAndroid.getDatabase().rawQuery(query, null);
}

我编写了与UltimateViewAdapter兼容的RecyclerView.Adapter<VH>实现(EventCursorRecyclerAdapter),它包含一个CursorAdapter成员以便使用数据库(代码基于this solution)。 ActiveAndroid(issue #3)中没有ContentObservers,因此我在初始化期间在ContentProvider上注册了一个观察者。初始化如下:

  

片段类

protected UltimateRecyclerView listView;
private AbstractCursorRecyclerAdapter adapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    cursor = eventsCursor();
    cursor.setNotificationUri(getActivity().getContentResolver(),
                ContentProvider.createUri(Event.class, null));
    adapter = new EventCursorRecyclerAdapter(getActivity(), cursor, R.layout.list_item_event);

    getActivity().getSupportLoaderManager().initLoader(0, savedInstanceState, this);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    /* ... */

    // Configure RecyclerView
    listView.setLayoutManager(new LinearLayoutManager(getActivity()));
    listView.setAdapter(adapter);
}

我使用ActiveAndroid的ContentProvider(docs)为CursorLoader创建URI:

  

的AndroidManifest.xml

<application ...>
    <provider
        android:name="com.activeandroid.content.ContentProvider"
        android:authorities="com.activeandroid.content.ContentProvider"
        android:exported="false" />
    ...
</application>
  

LoaderManager.LoaderCallbacks<T>实施

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle cursor) {
    return new CursorLoader(
            MyFragment.this.getActivity(),
            ContentProvider.createUri(Event.class, null),
            null, null, null, null);
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    adapter.asCursorAdapter().changeCursor(data);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    adapter.asCursorAdapter().changeCursor(null);
}

当我检测到数据集中的更改时,我调用

MyFragment.this.getActivity().getContentResolver().notifyChange(
        ContentProvider.createUri(Event.class, modifiedId), null);

我不知道为什么,但它不起作用。没有数据显示,没有记录错误。

更新适配器的完整代码(提醒matryoshka)

  

EventCursorAdapter

public class EventCursorAdapter extends CursorAdapter {

    private final int itemLayoutId;
    private final LayoutInflater inflater;

    /**
     * @param itemLayoutId List item layout
     */
    public EventCursorAdapter(Context context, Cursor cursor, @LayoutRes int itemLayoutId) {
        super(context, cursor, 0);
        this.itemLayoutId = itemLayoutId;
        this.inflater = LayoutInflater.from(context);
    }

    /**
     * It is used to inflate a new view and return it.
     *
     * @return a new View
     */
    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return inflater.inflate(itemLayoutId, parent, false);
    }

    /**
     * Bind all data to a given view (such as setting the text on a TextView).
     */
    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        EventItemViewHolder holder = (EventItemViewHolder) view.getTag();

        // Extract properties and populate fields
        holder.tvName.setText(cursor.getString(holder.nameIndex));
        /* ... */
    }
}
  

EventCursorRecyclerAdapter

public final class EventCursorRecyclerAdapter extends AbstractCursorRecyclerAdapter {

    /**
     * @param itemLayoutId List item layout
     */
    public EventCursorRecyclerAdapter(Context context, Cursor cursor, @LayoutRes int itemLayoutId) {
        super(new EventCursorAdapter(context, cursor, itemLayoutId), context);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        // Passing the binding operation to cursor loader
        cursorAdapter.bindView(holder.itemView, context, cursorAdapter.getCursor());
    }

    @Override
    public UltimateRecyclerviewViewHolder onCreateViewHolder(ViewGroup parent) {
        // Passing the inflater job to the cursor-adapter
        View v = cursorAdapter.newView(context, cursorAdapter.getCursor(), parent);
        return new EventItemViewHolder(v, cursorAdapter.getCursor());
    }

    /**
     * See ViewHolder Pattern.
     */
    public final class EventItemViewHolder extends UltimateRecyclerviewViewHolder {

        // Column indices
        int nameIndex, timeIndex /*, ...*/;

        // Views
        TextView tvName, tvTime;
        /* ... */

        public EventItemViewHolder(View view, Cursor cursor) {
            super(view);

            // Find fields to populate in inflated template
            tvName = (TextView) view.findViewById(R.id.tv_event_name);
            tvTime = (TextView) view.findViewById(R.id.tv_event_time);
            /* ... */

            // Find columns
            nameIndex = cursor.getColumnIndexOrThrow("name");
            timeIndex = cursor.getColumnIndexOrThrow("time");
        }

    }
}
  

AbstractCursorRecyclerAdapter

public abstract class AbstractCursorRecyclerAdapter extends UltimateViewAdapter {

    // PATCH: Because RecyclerView.Adapter in its current form doesn't natively support cursors,
    // we "wrap" a CursorAdapter that will do all teh job for us
    protected final CursorAdapter cursorAdapter;
    protected final Context context;

    public AbstractCursorRecyclerAdapter(CursorAdapter cursorAdapter, Context context) {
        setHasStableIds(true);
        this.cursorAdapter = cursorAdapter;
        this.context = context;
    }

    @Override
    public int getAdapterItemCount() {
        return cursorAdapter.getCount();
    }

    @Override
    public long getItemId(int position) {
        return cursorAdapter.getItemId(position);
    }

    private Model getItem(int position) {
        return (Model) cursorAdapter.getItem(position);
    }

    public CursorAdapter asCursorAdapter() {
        return cursorAdapter;
    }

    public void remove(int position) {
        Model entity = getItem(position);
        if (entity != null) {
            entity.delete();
            notifyDataSetChanged();
        }
    }
}
  

Gradle依赖

compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
compile 'com.marshalchen.ultimaterecyclerview:library:0.3.2'

0 个答案:

没有答案