
guide
Tutti i linguaggi per diventare uno sviluppatore di app per Android.
Cos’è e come funziona la RecyclerView, che permette di visualizzare liste interattive di moltissimi elementi in modo efficiente.
Nella guida allo sviluppo di GUI per Android, sono stati discussi diversi elementi grafici, come le Toolbar ed i Floating Action Button (FAB), che compongono ormai da anni le interfacce delle più moderne applicazioni Android.
Tra tutti, il componente fondamentale della quasi totalità delle applicazioni esistenti è il RecyclerView
, introdotto con un esempio pratico in questa lezione.
Questo componente ha offerto fin dalle sue prime implementazioni (risalenti al 2014, con il rilascio di Android Lollipop) un nuovo approccio nella risoluzione di un problema comune: la creazione di liste per la visualizzazione di dati ottenuti da un servizio remoto o da un database locale.
In questo approfondimento, vedremo più nel dettaglio i suoi componenti per capirne a pieno il funzionamento.
È ormai un’usanza comune presentare all’utente una lista di elementi contenente un sottoinsieme di informazioni che la caratterizzano (come foto, un titolo e un sottotitolo) per aiutarlo nella scelta di quale dettaglio consultare. Dal punto di vista dello sviluppo, la realizzazione di questi elementi si riporta alla definizione di un insieme di View
da popolare con le informazioni da mostrare nella viewport, ossia la porzione di schermo visibile dall’utente.
Nonostante venga visualizzato solo un sottoinsieme di elementi sullo schermo, in realtà l’applicazione deve creare il layout anche per tutti gli elementi che non sono visibili nella schermata, senza contare che ogni elemento visualizzato deve essere salvato in memoria per poterlo mostrare in un secondo momento all’utente senza doverlo ricreare.
Questo meccanismo è trascurabile nel caso in cui si debba lavorare con liste di piccole dimensioni. In caso contrario, però, diventa impraticabile utilizzare questo approccio. Purtroppo, il caricamento di un grande insieme di elementi in una sola volta porta ad una rapida saturazione delle memoria, con impatti spiacevoli sulla user experience e sulle prestazioni dell’applicazione.
È qui che viene in aiuto il componente RecyclerView
.
Anziché creare tutti gli elementi della lista durante lo scroll, esso mantiene in una coda, chiamata recycler bin (cestino per il riciclaggio), alcuni degli elementi precedentemente visualizzati per riutilizzarli in un secondo momento. Infatti, durante lo scorrimento della lista, il RecyclerView
recupererà dalla coda un elemento e lo popolerà con le nuove informazioni da mostrare all’utente.
Proprio questo meccanismo di riciclo e i vantaggi offerti (riportati nella tabella seguente) hanno fatto sì che il RecyclerView
si affermasse in questi anni come soluzione principe nella creazione delle liste, sostituendo completamente il suo predecessore: la ListView.
Pro | Riciclo delle viste attraverso l’utilizzo del pattern ViewHolder |
---|---|
Supporto di liste orizzontali, verticali, grid classiche e sfalsate (staggered grid) | |
Supporto per lo scroll orizzontale e verticale (non disponibile con il ListView ) |
|
Miglioramenti in termini di performance e di occupazione della memoria in quanto non è necessario creare il layout da popolare con le informazioni del data source per via del riutilizzo | |
Integrazione di animazioni per aggiungere, aggiornare e rimuovere oggetti | |
Contro | Aumento della complessità |
Mancanza di un metodo nativo per intercettare il click su un elemento della lista |
Uno degli aspetti più interessanti del RecyclerView
è proprio la sua modularità, che lo rende facilmente modificabile e riutilizzabile in diversi punti dell’applicazione.
Nella seguente figura, è riportato un semplice schema di comunicazione tra i componenti coinvolti nella creazione di una lista tramite il RecyclerView
.
Vediamo nel dettaglio ciascuno di tali componenti.
Componente | Tipologia | Descrizione |
---|---|---|
Adapter | RecyclerView.Adapter |
È responsabile di estrarre i dati dal Data Source e di usare questi dati per creare e popolare i ViewHolder . Quest’ultimi saranno poi inviati al Layout Manager del RecyclerView.Adapter . |
ViewHolder | RecyclerView.ViewHolder |
È la chiave di volta tra il RecyclerView e l’Adapter e permette la riduzione nel numero di view da creare. Questo oggetto infatti fornisce il layout da popolare con i dati presenti nel DataSource e viene riutilizzato dal RecyclerView per ridurre il numero di layout da creare per popolare la lista. |
Layout Manager | RecyclerView.LayoutManager |
È responsabile della creazione e del posizionamento delle view all’interno del RecyclerView . Esistono diverse tipologie di LayoutManager come il LinearLayoutManager utilizzato per creare liste orizzontali o verticali. |
DataSource | List |
È l’insieme di dati utilizzato per popolare la lista tramite l’Adapter |
Creiamo un nuovo progetto Android, come illustrato in questa lezione, e chiamiamolo RecyclerViewHMTLit.
Nell’app gradle aggiungiamo alcune librerie, che ci permetteranno di gestire:
RecyclerView
;
dependencies {
// ...
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}
Dopo aver configurato correttamente tutte le librerie a nostra disposizione, siamo pronti per creare la nostra lista con RecyclerView
e a comprenderne il meccanismo di riciclo dei ViewHolder
con un semplice esempio basato sul colore del nostro ViewHolder
.
Per fare ciò i passi da compiere sono i seguenti:
ViewHolder
creato;RecyclerView
e creazione di un apposito layout per il ViewHolder
;Adapter
e del ViewHolder
;RecyclerView
nella MainActivity
.All’interno del nostro package principale definiamo un nuovo package di nome utils e creiamo la classe ColorUtils
definita qui.
Questa classe definisce al suo interno il metodo statico seguente:
public static int getViewHolderBackgroundColorFromInstance(Context context, int instanceNum){..}
Esso, dato il contesto dell’applicazione e un intero che rappresenta l’ordine in cui il ViewHolder
è stato creato, ritorna un intero che rappresenta il colore da utilizzare come background.
Nonostante la sua semplicità, questo metodo è fondamentale per capire come i ViewHolder
vengano riciclati all’interno di un RecyclerView
.
Non resta che definire l’asset di colori. In questo caso, definiamo all’interno del file colors.xml (consultabile a questo link) un gradiente di colori che va dal bianco all’arancione passando per il giallo.
Apriamo il layout della MainActivity
, activity_main.xml, e sostituiamo la TextView
di default con il componente RecyclerView
come segue.
...
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_colored"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
...
Creiamo quindi un nuovo layout, che verrà utilizzato dal ViewHolder
e popolato a run-time dall’Adapter
. Chiamiamo questo layout list_item e definiamo al suo interno un FrameLayout
contenente:
ImageView
che mostrerà il logo di HTML.itTextView
che mostrerà un numero corrispondente alla reale posizione dell’elemento nella lista;TextView
contenente l’effettivo indice del ViewHolder
che ci permetterà di capire come vengono ri-utilizzati i ViewHolder
creati.Per completezza, si riporta al seguente link l’implementazione del layout list_item.
Creiamo ora un nuovo package che conterrà al suo interno l’Adapter
ed il relativo ViewHolder
. Chiamiamo il nuovo package Adapter
, ed al suo interno creiamo una nuova classe ItemAdapter
.
Per poter implementare appieno la classe ItemAdapter
è necessario creare prima la classe ItemViewHolder
come inner class.
l’implementazione della classe ItemViewHolder
è alquanto semplice. Tramite ButterKnife facciamo il binding tra gli elementi del layout list_item creato in precedenza e i relativi oggetti View
che li caratterizzano in Java. Successivamente, definiamo il costruttore della classe in cui effettuiamo il binding tramite ButterKnife e implementiamo il metodo bind
che ha il compito di impostare il testo rappresentante la posizione dell’elemento corrente.
public class ItemAdapter {
// ...
class ItemViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.tv_item_number)
TextView mListItemNumberTV;
@BindView(R.id.tv_view_holder_index)
TextView mVHIndexTV;
@BindView(R.id.iv_logo)
ImageView mIVLogp;
public ItemViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
void bind(int listIndex) {
mListItemNumberTV.setText(String.valueOf(listIndex));
}
}
}
Ora possiamo finalmente estendere la classe RecyclerView.Adapter
come segue.
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemViewHolder> {
private static int viewHolderCount;
private int mNumberItems;
private Context parentContex;
public ItemAdapter(int numberOfItems) {
mNumberItems = numberOfItems;
viewHolderCount = 0;
}
//...
}
In particolare, abbiamo definito tre attributi che corrispondono al numero di ViewHolder
creati, al numero di elementi della lista totali e al Context
del parent, e abbiamo definito il costruttore della classe.
Per mostrare il meccanismo di riciclo, però, dobbiamo implementare i metodi onCreateViewHolder
e onBindViewHolder
propri della classe RecyclerView.Adapter
.
In particolare, nel metodo onCreateViewHolder
andiamo ad abilitare la creazione di un nuovo ItemViewHolder
, che come parametro prende in ingresso un oggetto di tipo View
, ossia il layout list_item. Creato l’oggetto, impostiamo il colore di background invocando il metodo getViewHolderBackgroundColorFromInstance
della classe ColorUtils
sulla base del valore corrente del viewHolderCount
. Infine, impostiamo l’informazione su quale ViewHolder
stiamo visualizzando e incrementiamo di un’unità la proprietà viewHolderCount
.
@Override
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
parentContex = parent.getContext();
int layoutIdForListItem = R.layout.list_item;
LayoutInflater inflater = LayoutInflater.from(parentContex);
View view = inflater.inflate(layoutIdForListItem, parent, false);
ItemViewHolder holder = new ItemViewHolder(view);
int backgroundColorForViewHolder = ColorUtils
.getViewHolderBackgroundColorFromInstance(parentContex, viewHolderCount);
holder.mVHIndexTV.setText("ViewHolder index: " + viewHolderCount);
holder.itemView.setBackgroundColor(backgroundColorForViewHolder);
viewHolderCount++;
return holder;
}
Nel metodo onBindViewHolder
, invece, andiamo a compiere solo due semplici operazioni:
bind
della classe ItemViewHolder
per impostare la posizione corrente dell’elemento;
@Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
holder.bind(position);
Picasso.get()
.load(R.drawable.logo_open)
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher)
.into(holder.mIVLogp);
}
Spostiamoci adesso sulla MainActivity
per implementare la RecyclerView
e il metodo di reset della lista.
Definiamo tre variabili per rappresentare il numero di elementi nella lista, il RecyclerView
e l’Adapter
per quest’ultimo. Inoltre, aggiungiamo la notazione @BindView
per il RecyclerView
in modo da mapparlo successivamente nel metodo onCreate
.
private static final int NUM_LIST_ITEMS = 100;
private ItemAdapter mAdapter;
@BindView(R.id.rv_colored)
RecyclerView mList;
Nel metodo onCreate
, eseguiamo i seguenti passi:
ButterKnife
;LayoutManager
di tipo LinearLayoutManager
e lo associamo al RecyclerView
;adapter
di tipo ItemAdapter
a cui passiamo il numero di elementi da creare e lo associamo al RecyclerView
.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mList.setLayoutManager(layoutManager);
mList.setHasFixedSize(true);
mAdapter = new ItemAdapter(NUM_LIST_ITEMS);
mList.setAdapter(mAdapter);
}
Il RecyclerView
differentemente dal ListView
non offre un metodo nativo per intercettare il click su un elemento della lista. Per aggiungere tale comportamento basta compiere pochi semplici passi. Vediamoli insieme.
Sempre all’interno della classe ItemAdapter
, creiamo l’interfaccia ItemClickListener
che riceve il messaggio di clic e definiamo una variabile statica per il listener
:
final private ItemClickListener mOnClickListener;
public interface ItemClickListener {
void onListItemClick(int clickedItemIndex);
}
Modifichiamo il costruttore della classe ItemAdapter
per passare il listener e salvarlo nella variabile mOnClickListener
:
public ItemAdapter(int numberOfItems, ItemClickListener listener) {
// . . .
mOnClickListener = listener;
}
Implementiamo la classe ItemViewHolder
con l’interfaccia View.OnClickListener
per implementare il metodo onClick
che verrà invocato ogni qualvolta l’utente cliccherà su un elemento della lista.
class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//...
public ItemViewHolder(View itemView) {
// ...
itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
int clickedPosition = getAdapterPosition();
mOnClickListener.onListItemClick(clickedPosition);
}
}
Infine, modifichiamo come segue la MainActivity
per implementare l’interfaccia ItemClickListener
e modificare la creazione dell’ItemAdapter
.
public class MainActivity extends AppCompatActivity implements ItemAdapter.ItemClickListener {
// ...
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
mAdapter = new ItemAdapter(NUM_LIST_ITEMS, this);
mNumbersList.setAdapter(mAdapter);
}
@Override
public void onListItemClick(int clickedItemIndex) {
if (mToast != null) {
mToast.cancel();
}
String toastMessage = "Item #" + clickedItemIndex + " clicked.";
mToast = Toast.makeText(this, toastMessage, Toast.LENGTH_LONG);
mToast.show();
}
}
Eseguiamo infine la nostra applicazione per vedere effettivamente il risultato del lavoro fatto.
Come è possibile vedere, l’applicazione ci mostra una lista di elementi composti da:
ViewHolder
che è stato creato e visualizzato.In questo caso, scorrendo la lista si può notare che il numero relativo della posizione aumenta e il colore del background cambia finché non si raggiunge il ViewHolder
avente come indice il valore 12.
Dall’elemento 13 della lista in poi, il RecyclerView
mette in moto il meccanismo di riciclo dei ViewHolder
, recuperandoli dal recycle bin per popolarli con le nuove informazioni fornite dall’Adapter
.
Si potrebbe (erroneamente) pensare che il RecyclerView
ritulizzi in modo ordinato i 13 ViewHolder
creati, ma in realtà non è così.
Come mostrato nella Figura 2, scorrendo velocemente la lista e poi osservandola, si può notare l’efficienza del meccanismo di riciclo che recupera dal suo recycler bin i ViewHolder
in quel momento disponibili e li mostra all’utente finale senza perdite in termini di prestazioni.
Questo ovviamente si traduce in una lista in cui le informazioni restano sempre le stesse, ma ciò che cambia è l’ordine in cui i ViewHolder sono utilizzati dal RecyclerView
.
Infine, cliccando su uno degli elementi comparirà un Toast
che ci comunicherà quale elemento è stato cliccato.
Questo meccanismo ha fatto sì che RecyclerView
diventasse lo strumento principale per la realizzazione di liste, nonostante la sua implementazione non sia così rapida come quella del ListView
di cui si è parlato in precedenza qui.
Il codice di questa lezione è disponibile su GitHub.
Se vuoi aggiornamenti su Android, mobile inserisci la tua email nel box qui sotto:
Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.
La tua iscrizione è andata a buon fine. Se vuoi ricevere informazioni personalizzate compila anche i seguenti campi opzionali:
Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.
Dare una chance a linguaggi dichiarativi e funzionali
Tutti i linguaggi per diventare uno sviluppatore di app per Android.
Come creare applicazioni per il Web con PHP e MySQL per il DBMS.
Tutte le principali tecnologie per diventare uno sviluppatore mobile per iOS.
I fondamentali per lo sviluppo di applicazioni multi piattaforma con Java.
Diventare degli esperti in tema di sicurezza delle applicazioni Java.
Usare Raspberry Pi e Arduino per avvicinarsi al mondo dei Maker e dell’IoT.
Le principali guide di HTML.it per diventare un esperto dei database NoSQL.
Ecco come i professionisti creano applicazioni per il Cloud con PHP.
Lo sviluppo professionale di applicazioni in PHP alla portata di tutti.
Come sviluppare applicazioni Web dinamiche con PHP e JavaScript.
Fare gli e-commerce developer con Magento, Prestashop e WooCommerce.
Realizzare applicazioni per il Web utilizzando i framework PHP.
Creare applicazioni PHP e gestire l’ambiente di sviluppo come un pro.
Percorso base per avvicinarsi al web design con un occhio al mobile.
Realizzare siti Web e Web application con WordPress a livello professionale.
Il supporto alla comunicazione basata su Intent è molto comodo per l’interoperabilità su Android, ma espone le app a potenziali attacchi di spoofing.
Un tutorial completo ed esaustivo che mostra come integrare ed utilizzare le YouTube API per sviluppare un’app mobile per Android.
Guida pratica all’implementazione di un’app per Android in grado di sfruttare le funzionalità messe a disposizione per la realtà virtuale.
Android è il sistema operativo mobile più diffuso attualmente sul mercato. Imparare a sviluppare app per Android è quindi la chiave d’accesso ad uno dei mercati più attivi nello sviluppo mobile. Questa guida completa e dettagliata fornisce tutte le informazioni necessarie per imparare a progettare ed implementare app moderne e funzionali per Android.