Recyclerview + 内容提供者 + CursorLoader

Posted

技术标签:

【中文标题】Recyclerview + 内容提供者 + CursorLoader【英文标题】:Recyclerview + Content provider + CursorLoader 【发布时间】:2015-02-28 02:40:18 【问题描述】:

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

另外,任何人都可以解释为什么我们需要将数据从光标传输到对象以显示在列表视图/回收器视图中,而不是直接从光标传输?

例如,在自定义的 cursorAdapter 类中,

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

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

以上方法哪一种更好?

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

【问题讨论】:

您不必使用任何列表:使用 ItemBridgeAdapter + CursorObjectAdapter 或直接在您的自定义 RecyclerView.Adapter 中绑定 Cursor 老实说,我不知道为什么 CursorObjectAdapter 在为电视设备设计的“​​leanback”支持库中,恕我直言,它应该是任何“通用”支持库的一部分 @pskink 我现在必须解决这个问题。请您提供一个简短的例子来说明我如何bind the Cursor directly in [my] custom RecyclerView.Adapter?这将非常有帮助。谢谢。当你这样做时,请在回复的评论中标记我,我知道。感谢您提供的任何帮助。 @KatedralPillon 例如:gist.github.com/Shywim/127f207e7248fe48400b @KatedralPillon 当然!永远不要将光标加载到任何列表中,似乎这里 99% 的人做了一件我不知道为什么这么愚蠢的事情(他们需要一个自定义适配器(对于 ListView,这是一个自定义 BaseAdapter/ArrayAdapter)/他们需要一个 POJO 来保存数据/他们需要一个循环来遍历游标)为什么???我不知道 【参考方案1】:

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

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 就可以了

【讨论】:

您说:“所以您需要提前从数据库中获取所有对象”,但是如果我有 12.000 个对象要从数据库中获取怎么办,这是选择 ContentProvider 机制的主要原因(为我做延迟加载)? 你应该如何使数组与数据库保持同步?【参考方案2】:

有几个 Github 要点/项目,如 this 和 this 展示了这样的用例。

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

【讨论】:

【参考方案3】:

我认为您可以直接将自定义 CursorAdapter 用于 RecyclerView,这样您就不必将 Cursor 转换为 数组列表

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

希望它对你有用。 :)

【讨论】:

***.com/questions/39825125/…

以上是关于Recyclerview + 内容提供者 + CursorLoader的主要内容,如果未能解决你的问题,请参考以下文章

Android RecyclerView使用方法详解

Android RecyclerView体验- 简介

exchange2013 CU13数据库内容索引失败

Recyclerview 没有填充 JSON 和 Retrofit?

删除单个 SQlite 行 RecyclerView onSwiped

RecyclerView 内容高度