2014-10-29 3 views
34

Desidero implementare la funzionalità di ricerca per il mio RecyclerView. Sul testo cambiato voglio cambiare i dati che vengono visualizzati con questo widget. Forse questa domanda è stato chiesto prima o è semplice, ma non so come il cambiamento dei dati che devono essere visualizzati ...RecyclerView cambia set di dati

mio RecyclerView è definito come segue:

 // 1. get a reference to recyclerView 
    mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView); 

    // 2. set layoutManger 
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 
    // 3. create an adapter 
    mAdapter = new ItemsAdapter(itemsData); 
    // 4. set adapter 
    mRecyclerView.setAdapter(mAdapter); 

E il dati che sto mostrando è qualcosa di simile:

ItemData itemsData[] = { new ItemData("Mary Richards"), 
     new ItemData("Tom Brown"), 
     new ItemData("Lucy London")   
}; 

Così, quando, quando voglio dare l'adattatore un'altra serie di dati, un altro array (con una sola voce per esempio), che cosa devo fare?

+0

Se si vuole dare un altro array si può semplicemente creare un nuovo 'ItemsAdapter' con esso e chiamare' setAdapter' di nuovo. –

risposta

74

Se hai ids stabili nel vostro adattatore, è possibile ottenere buoni risultati (animazioni) se si crea un nuovo array contenente gli elementi filtrati e chiamare

recyclerView.swapAdapter(newAdapter, false); 

Utilizzando swapAdapter suggerimenti RecyclerView che possa riutilizzare i detentori di immagini. (vs in setAdapter, deve riciclare tutte le viste e ricreare perché non sa che il nuovo adattatore ha lo stesso ViewHolder impostato con il vecchio adattatore).

Un approccio migliore sarebbe trovare quali elementi vengono rimossi e chiamando notifyItemRemoved(index). Non dimenticare di rimuovere effettivamente l'oggetto. Ciò consentirà a RecyclerView di eseguire animazioni predittive. Supponendo di avere un adattatore che utilizza internamente un ArrayList, implementazione sarebbe simile a questa:

// adapter code 
final List<ItemData> mItems = new ArrayList(); //contains your items 
public void filterOut(String filter) { 
    final int size = mItems.size(); 
    for(int i = size - 1; i>= 0; i--) { 
     if (mItems.get(i).test(filter) == false) { 
      mItems.remove(i); 
      notifyItemRemoved(i); 
     } 
    } 
} 

Si sarebbe eseguire ancora meglio se si può ammucchiare notifyItemRemoved chiamate e utilizzare notifyItemRangeRemoved invece. Sembrerebbe STH come: (non testato)

public void filterOut(String filter) { 
    final int size = mItems.size(); 
    int batchCount = 0; // continuous # of items that are being removed 
    for(int i = size - 1; i>= 0; i--) { 
     if (mItems.get(i).test(filter) == false) { 
      mItems.remove(i); 
      batchCount ++; 
     } else if (batchCount != 0) { // dispatch batch 
      notifyItemRangeRemoved(i + 1, batchCount); 
      batchCount = 0; 
     } 
    } 
    // notify for remaining 
    if (batchCount != 0) { // dispatch remaining 
     notifyItemRangeRemoved(0, batchCount); 
    } 
} 

È necessario estendere questo codice per aggiungere elementi che sono stati precedentemente filtrati, ma ora dovrebbe essere visibile (ad esempio utente elimina la query del filtro), ma penso che questo si dovrebbe dare l'idea di base.

Ricordare che ogni chiamata di elemento di notifica influisce su quelli successivi (motivo per cui sto attraversando l'elenco da fine per evitarlo). Attraversare da fine aiuta anche le prestazioni del metodo di rimozione di ArrayList (meno elementi da spostare).

Ad esempio, se si stava attraversando l'elenco dall'inizio e si rimuovono i primi due elementi. Si dovrebbe neanche chiamare

notifyItemRangeRemoved(0, 2); // 2 items starting from index 0 

o se la spedizione uno per uno

notifyItemRemoved(0); 
notifyItemRemoved(0);//because after the previous one is removed, this item is at position 0 
+0

Grazie per la vostra risposta, apporterò delle modifiche che si adattano alle mie esigenze, ma questo è ciò di cui avevo bisogno in pratica. L'hai spiegato molto bene. – Sandra

+1

Che cosa significa "ID stabili"? Il mio set di dati cambia ma non so in che modo (alcuni nuovi elementi potrebbero essere aggiunti e alcuni potrebbero essere rimossi), tuttavia la vista rimane invariata, quindi dovrei passare true o false a swapAdapter? –

2

Basta re-inizializzare l'adattatore:

mAdapter = new ItemsAdapter (newItemsData);

o se avete solo bisogno di rimuovere aggiungere alcuni elementi specifici, piuttosto che un intero elenco:

mAdapter. notifyItemInserted (posizione);

o

mAdapter.notiftyItemRemoved (posizione);

22

Questa è la mia risposta - grazie a Ivan Skoric dal suo sito: http://blog.lovelyhq.com/creating-lists-with-recyclerview-in-android/

ho creato un metodo in più all'interno della mia classe adattatore:

public void updateList(List<Data> data) { 
    mData = data; 
    notifyDataSetChanged(); 
} 

Quindi ogni volta i nostri dati cambiano, tu chiami questo metodo passando i tuoi nuovi dati e la tua vista dovrebbe cambiare per rispecchiarli.

+0

notifyDataSetChanged() uccide tutte le animazioni, valido solo per le grandi liste. – Davidea

+0

@Davidea ... che è il tipico caso d'uso di RecyclerView –

+0

Un recyclerView conserva solo le viste visibili in memoria e le rilascia quando le si sfoglia dallo schermo. È altamente efficiente da una prospettiva di memoria rispetto ad una listview. Funzionano come un listview. Puoi leggere i documenti di recyclerview qui: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html – Simon

0

As ygit ha risposto, swapAdapter è interessante quando è necessario modificare l'intero contenuto.

Tuttavia, nel mio FlexibleAdapter, è possibile aggiornare gli articoli con updateDataSet. È anche possibile configurare l'adattatore per chiamare notifyDataSetChanged o con animazioni di sincronizzazione (abilitato per impostazione predefinita). Questo, perché notifyDataSetChanged uccide tutte le animazioni, ma è bello avere per le grandi liste.

Si prega di dare un'occhiata alla descrizione, demoApp e Wiki: https://github.com/davideas/FlexibleAdapter