20

Ho alcuni dati nel database SQLite. Ho un fornitore di contenuti che otterrà i dati dal database. Ora il problema è come implementare cursorLoader per funzionare con recyclerview?Recyclerview + Content provider + CursorLoader

Inoltre, chiunque può spiegare perché è necessario trasferire i dati dal cursore a un oggetto per visualizzarli in un listview/recyclerview e non direttamente da un cursore?

Per esempio, Nella classe CursorAdapter personalizzato,

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

O

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

Quale uno dei metodo di cui sopra è meglio?

In passato, avevamo listview e gridview e sembra che ora siano combinati per diventare recyclerview. Quindi, come posso implementare un recyclerview basato sulla griglia?

+0

non dovete utilizzare qualsiasi elenco: utilizzare ItemBridgeAdapter + CursorObjectAdapter o legare il cursore direttamente nella tua RecyclerView.Adapter personalizzato – pskink

+0

onestamente non so il motivo per cui CursorObjectAdapter è in "Leanback" libreria di supporto che è stato progettato per i dispositivi TV, imho dovrebbe essere parte di qualsiasi libreria di supporto "scopi generali" – pskink

+0

@pskink Devo risolvere questo problema al momento. Vi preghiamo di fornire un breve esempio di come posso "legare il cursore direttamente in [mio] RecyclerView.Adapter personalizzato"? Sarebbe tremendamente utile. Grazie. E per favore taggami nel commento della risposta quando lo fai, lo so. Grazie per tutto l'aiuto che potete fornire. –

risposta

4

In generale si dovrebbe cercare di separare le responsabilità di visualizzazione e dati. Quindi, ciò che è necessario è quello di ottenere tutti gli oggetti dal database di anticipo quindi impostare un adattatore che si presenta come il seguente:

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

Quindi è possibile associare l'adattatore al RecyclerView da:

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

per rispondere alla tua seconda domanda ("In passato, abbiamo utilizzato per avere ListView e gridView e sembra ora sono combinati per diventare recyclerview Allora, come faccio a implementare un recyclerview griglia di base.?"):

Quando vincolante un LayoutManager per RecyclerView puoi decidere quale uno si prende:

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

o

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

Ci sono diversi LayoutManagers. Scopri di più here.

UPDATE: Non è necessario caricare tutti gli elementi di anticipo, basta rinominare setItems a addItems e vi sono buone per andare

+1

Tu dici: "Quindi quello che ti serve è ottenere tutti gli oggetti dal database in anticipo", ma cosa succede se ho 12.000 oggetti da recuperare dal database , e questo è il motivo principale per cui scegliere il meccanismo ContentProvider (per fare il caricamento pigro per me)? – miroslavign

+0

Come si suppone di mantenere la matrice in sincronia con il database? – 0xcaff

3

Ci sono diversi Github GIST/progetti come this e this che mostrano un tale utilizzo Astuccio.

Mentre si utilizza un adattatore che è adattato in modo personalizzato a un adattatore del cursore, si utilizzerà un GridLayoutManager/LinearLayoutManager come al solito per lo stesso.

1

Penso che si può utilizzare direttamente con clienti CursorAdapter per RecyclerView quindi non c'è bisogno di convertire cursore a 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); 
     } 
    } 
} 

maggio sarà utile a voi.:)