Recyclerview + Content provider + CursorLoader

时间:2015-01-01 12:18:55

标签: android sqlite cursor android-contentprovider android-recyclerview

我在SQLite数据库中有一些数据。我有一个内容提供程序,它将从数据库中获取数据。现在问题是如何实现cursorLoader与recyclerview一起工作?

此外,任何人都可以解释为什么我们需要将数据从游标传输到对象以显示在listview / recyclerview中而不是直接从游标中显示?

例如,在自定义cursorAdapter类中,

Person person = new Person(cursor.getString(cursor.getColumnIndexOrThrow(PERSON_NAME)));
textview.setText = person.getName();

OR

textview.setText = cursor.getString(cursor.getColumnIndexOrThrow(PERSON_NAME));

上述哪种方法更好?

过去,我们曾经有过listview和gridview,现在看来它们被合并成了recyclerview。那么,我如何实现基于网格的Recyclerview?

3 个答案:

答案 0 :(得分:4)

通常,您应该尝试分离视图和数据职责。所以你需要的是提前从数据库中获取所有对象,然后设置一个如下所示的适配器:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private final List<Person> objectList = new ArrayList<>();

    @Override
    public CustomAdapter.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
        final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        return new ViewHolder(layoutInflater.inflate(R.layout.adapter_item, parent, false));
    }

    @Override
    public void onBindViewHolder(final CustomAdapter.ViewHolder holder, final int position) {
        holder.bindItem(objectList.get(position));
    }

    // Set the persons for your adapter
    public void setItems(final List<Person> persons) {
        objectList.addAll(persons);
        notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        return objectList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final TextView mTextViewTitle;
        private Object mObject;

        public ViewHolder(final View itemView) {
            super(itemView);
            mTextViewTitle = (TextView) itemView.findViewById(R.id.view_item_textViewTitle);                
            mTextViewTitle.setText(mObject.getText());
        }

        private void bindItem(@NonNull final Person object) {
            mObject = object;
        }
    }
}

然后您可以通过以下方式将适配器绑定到RecyclerView:

final CustomAdapter adapter = new CustomAdapter();
adapter.setItems(mPersons);
mRecyclerView.setAdapter();

回答你的第二个问题(“过去,我们过去常常使用listview和gridview,现在看来它们合并成了recyclerview。那么,我如何实现基于网格的Recyclerview?”):

将LayoutManager绑定到RecyclerView时,您可以决定使用哪一个:

final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);

final GridLayoutManager layoutManager = new GridLayoutManager(this, COLUMN_SPAN_COUNT);
mRecyclerView.setLayoutManager(layoutManager);

有几个LayoutManagers。了解更多here

更新: 您不必提前加载所有项目,只需将setItems重命名为addItems,就可以了。

答案 1 :(得分:3)

有几个Github gists /项目,如thisthis,显示了这样一个用例。

虽然您将使用为游标适配器定制的适配器,但您可以像往常一样使用GridLayoutManager / LinearLayoutManager。

答案 2 :(得分:1)

我认为您可以直接使用自定义 CursorAdapter RecyclerView ,因此您无需转换光标 ArrayList

public class ProductListAdapter extends RecyclerView.Adapter<ProductListAdapter.ViewHolder> {

    // Because RecyclerView.Adapter in its current form doesn't natively 
    // support cursors, we wrap a CursorAdapter that will do all the job
    // for us.
    CursorAdapter mCursorAdapter;

    Activity mContext;
    Random rnd;

    public ProductListAdapter(AppCompatActivity context, Cursor c) {

        mContext = context;
        rnd = new Random();

        mCursorAdapter = new CursorAdapter(mContext, c, 0) {

            @Override
            public View newView(Context context, Cursor cursor, ViewGroup parent) {
                // Inflate the view here
                LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
                return inflater.inflate(R.layout.row_product_layout_grid, parent, false);
            }

            @Override
            public void bindView(View view, Context context, Cursor cursor) {
                String productName = cursor.getString(cursor.getColumnIndex(TProduct.PRODUCT_NAME));

                // Binding operations
                ((TextView) view.findViewById(R.id.sub_product_name_text_view)).setText(productName);



                int color = Color.argb(200, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));

                String url = "http://dummyimage.com/300/" + color + "/ffffff&text=" + (cursor.getPosition() + 1);

                Picasso
                        .with(context)
                        .load(url)
                        .placeholder(R.mipmap.ic_launcher) // can also be a drawable
                        .into((ImageView) view.findViewById(R.id.sub_product_image_view));
            }
        };
    }

    public void reQuery(Cursor c) {
        if (mCursorAdapter != null) {
            mCursorAdapter.changeCursor(c);
            mCursorAdapter.notifyDataSetChanged();
        }
    }

    @Override
    public int getItemCount() {
        return mCursorAdapter.getCount();
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // Passing the binding operation to cursor loader
        mCursorAdapter.getCursor().moveToPosition(position); //EDITED: added this line as suggested in the comments below, thanks :)
        mCursorAdapter.bindView(holder.view, mContext, mCursorAdapter.getCursor());
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // Passing the inflater job to the cursor-adapter
        View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent);
        return new ViewHolder(v);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        View view;
        public ViewHolder(View itemView) {
            super(itemView);
            view = itemView.findViewById(R.id.product_row_card_view);
        }
    }
}

愿它对你有用。 :)