20

Ich habe einige Daten in SQLite-Datenbank. Ich habe einen Content-Provider, der die Daten aus der Datenbank erhalten wird. Nun ist das Problem, wie implementiere ich cursorLoader, um mit Recyclerview in der Hand zu arbeiten?Recyclerview + Content Provider + CursorLoader

Auch kann jeder erklären, warum wir die Daten vom Cursor auf ein Objekt übertragen müssen, um in einer Listview/Recyclerview und nicht direkt von einem Cursor angezeigt werden?

Zum Beispiel in der benutzerdefinierten Klasse Cursoradapter,

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

ODER

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

, die eine der oben genannte Methode ist besser?

In der Vergangenheit hatten wir Listenansicht und Gridview und es scheint, dass sie kombiniert werden, um Recyclerview zu werden. Wie implementiere ich dann eine gridbasierte Recyclerview?

+0

Sie müssen keine Liste verwenden: Verwenden Sie ItemBridgeAdapter + CursorObjectAdapter oder binden Sie den Cursor direkt in Ihrem benutzerdefinierten RecyclerView.Adapter – pskink

+0

ehrlich ich weiß nicht, warum CursorObjectAdapter ist in "leanback" Support-Bibliothek, die für TV-Geräte entwickelt wird, imho es sollte Teil einer "allgemeine Zwecke" Support-Bibliothek sein – pskink

+0

@pskink Ich muss dieses Problem derzeit lösen. Kannst du mir bitte ein kurzes Beispiel geben, wie ich den Cursor direkt in [meinen] benutzerdefinierten RecyclerView.Adapter' binden kann? Das wäre enorm hilfreich. Vielen Dank. Und bitte tag mich in den Kommentar der Antwort, wenn Sie dies tun, weiß ich. Vielen Dank für Ihre Hilfe. –

Antwort

4

Im Allgemeinen sollten Sie versuchen, die Verantwortlichkeiten für Ansichten und Daten zu trennen. Also, was Sie brauchen, ist auf alle Ihre Objekte aus der Datenbank im Voraus erhalten dann einen Adapter einrichten, die aussieht wie die folgende:

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

Dann können Sie den Adapter an den RecyclerView binden durch:

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

Um Ihre zweite Frage zu beantworten ("Früher haben wir Listenansicht und Gridview verwendet und es scheint, dass sie kombiniert werden, um Recyclerview zu werden. Dann, wie implementiere ich eine Grid-basierte Recyclerview?"):

Einen LayoutManager zum RecyclerView können Sie selbst bestimmen man Sie nehmen:

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

oder

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

Es gibt mehrere LayoutManagers sind. Erfahren Sie mehr here.

UPDATE: Sie müssen nicht alle Elemente im Voraus laden, nur setItems zu addItems umbenennen und Sie sind gut zu gehen

+1

Sie sagen: "Also, was Sie brauchen, ist, um alle Ihre Objekte aus der Datenbank im Voraus zu bekommen", aber was ist, wenn ich 12.000 Objekt aus der Datenbank abrufen , und das ist der Hauptgrund, den ContentProvider-Mechanismus zu wählen (um lazy loading für mich zu machen)? – miroslavign

+0

Wie wird das Array mit der Datenbank synchronisiert? – 0xcaff

3

Es gibt mehrere Github Logen/Projekte wie this und this, die eine Verwendung solcher zeigen Fall.

Während Sie einen Adapter verwenden würden, der auf einen Cursor-Adapter zugeschnitten ist, würden Sie wie gewohnt einen GridLayoutManager/LinearLayoutManager verwenden.

1

Ich glaube, Sie direkt Individuelle CursorAdapter für RecyclerView so haben können Sie nicht Cursor zu Arraylist zu konvertieren:

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

Kann es Ihnen von Nutzen sein wird.:)