Se ti stai chiedendo come funziona BaseAdapter Android, quando ha senso usarlo rispetto ad ArrayAdapter e a RecyclerView.Adapter e come scrivere codice Java pulito e riutilizzabile, questa guida fa per te. Vedremo passo passo come collegare un elenco di oggetti Java a una ListView, come creare layout personalizzati con immagini e testo e come mantenere buone performance anche con molte righe a schermo.
Nel corso dell’articolo analizzeremo in dettaglio la classe BaseAdapter Android, capiremo perché è diversa da ArrayAdapter e quali sono i limiti rispetto a RecyclerView.Adapter. Inoltre, troverai esempi di codice Java completi e commentati per gestire più tipi di layout, aggiornamenti dinamici dei dati, checkbox con selezione multipla e il pattern ViewHolder per evitare lag nello scroll. Tutti gli snippet sono pensati per essere copiati e incollati direttamente in Android Studio.
BaseAdapter in Android: guida completa con esempi in Java
In questa guida vediamo in dettaglio come usare BaseAdapter in Android per creare liste personalizzate con ListView; in particolare, capiremo quando ha senso usarlo (rispetto ad ArrayAdapter e a RecyclerView) e come strutturare il codice in modo pulito e performante, così da ottenere liste più chiare e veloci.

1. Introduzione a BaseAdapter
BaseAdapter Android Java è una classe astratta della libreria Android che funge da base per creare adapter personalizzati, usati tipicamente con viste come ListView e GridView. In altri termini, un adapter ha il compito di trasformare i dati (oggetti Java, array, liste) in viste da mostrare a schermo.
Invece, quando usi un BaseAdapter Android Java, puoi controllare completamente:
- Come viene creato il layout di ogni elemento della lista.
- Come vengono legati i dati ai widget (TextView, ImageView, ecc.).
- Come ottimizzare le performance riutilizzando le viste con il pattern ViewHolder.
Quando usare BaseAdapter Android rispetto ad ArrayAdapter
ArrayAdapter è comodo per casi semplici, ad esempio una lista di stringhe o un layout molto basilare. Tuttavia, con il crescere della complessità dell’interfaccia, diventa limitante quando:
- Ogni elemento deve mostrare più informazioni (es. testo + immagine + pulsanti).
- Devi gestire logiche differenti per alcuni elementi.
- Vuoi massima flessibilità sul layout.
In questi casi, BaseAdapter Android Java è preferibile perché, a differenza di un semplice ArrayAdapter, ti permette di gestire manualmente la creazione e il riuso delle viste tramite il metodo getView().
BaseAdapter Android Java vs RecyclerView
RecyclerView è il componente moderno e consigliato da Google per liste complesse e performanti; infatti offre molte funzionalità avanzate (layout manager, animazioni, decorazioni). Tuttavia, ListView con BaseAdapter è ancora utile quando:
- Stai mantenendo o aggiornando un progetto legacy che usa già
ListView. - Hai una lista relativamente semplice e non ti servono le funzionalità avanzate di
RecyclerView. - Vuoi capire i concetti di base di come funziona un adapter in Android.
2. Struttura di BaseAdapter Android Java e metodi principali
In particolare, per creare un adapter personalizzato estendendo BaseAdapter, in primo luogo devi implementare obbligatoriamente quattro metodi:
getCount()
In particolare, restituisce il numero totale di elementi nella lista (la dimensione dei dati). Di conseguenza, ListView usa questo valore per sapere quanti elementi visualizzare.
getItem(int position)
Allo stesso modo, restituisce l’oggetto dati alla posizione specificata. Questo è particolarmente utile quando devi recuperare l’elemento associato a una certa riga, ad esempio nella gestione dei click.
getItemId(int position)
Restituisce un ID univoco per l’elemento alla posizione indicata. In molti casi, pertanto, puoi semplicemente restituire la posizione stessa (se non hai un ID univoco nel modello).
getView(int position, View convertView, ViewGroup parent)

È il metodo più importante: infatti crea (o riutilizza) la vista da mostrare nella ListView per la posizione indicata. Qui:
- Inflate il layout XML dell’elemento se
convertViewènull. - Recuperi e/o crei il ViewHolder.
- Colleghi i dati (testi, immagini, ecc.) ai widget.
BaseAdapter Android con layout personalizzato (immagine + testo)
Uno degli scenari più comuni in cui ha senso usare BaseAdapter Android è quando devi mostrare, per ogni riga della ListView, sia un’immagine (ImageView) sia uno o più testi (TextView). In questi casi un semplice ArrayAdapter non basta più ed è molto più comodo definire un layout XML personalizzato e un adapter che sappia “gonfiarlo” (inflate) e popolarlo con i dati.

Di seguito un esempio minimale di adapter che estende BaseAdapter e utilizza un layout con ImageView + TextView (simile a una semplice lista di prodotti o di elementi di menu):
// Prodotto.java
public class Prodotto {
private String nome;
private int iconaResId;
public Prodotto(String nome, int iconaResId) {
this.nome = nome;
this.iconaResId = iconaResId;
}
public String getNome() {
return nome;
}
public int getIconaResId() {
return iconaResId;
}
}
// item_prodotto.xml (layout con ImageView + TextView)
// Vedi guida su <code>ListView Android</code> per dettagli sui layout
// ProdottoAdapter.java
// Adapter personalizzato basato su BaseAdapter Android
public class ProdottoAdapter extends BaseAdapter {
private Context context;
private List<Prodotto> prodotti;
private LayoutInflater inflater;
public ProdottoAdapter(Context context, List<Prodotto> prodotti) {
this.context = context;
this.prodotti = prodotti;
this.inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return prodotti.size();
}
@Override
public Object getItem(int position) {
return prodotti.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
private static class ViewHolder {
ImageView imageViewIcona;
TextView textViewNome;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
// Inflate del layout personalizzato per la riga
convertView = inflater.inflate(R.layout.item_prodotto, parent, false);
holder = new ViewHolder();
holder.imageViewIcona = convertView.findViewById(R.id.imageViewIcona);
holder.textViewNome = convertView.findViewById(R.id.textViewNome);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Recupero del prodotto corrente
Prodotto prodotto = prodotti.get(position);
// Binding dei dati ai widget
holder.textViewNome.setText(prodotto.getNome());
holder.imageViewIcona.setImageResource(prodotto.getIconaResId());
return convertView;
}
}
Come vedi, con BaseAdapter Android hai il pieno controllo sul layout della riga e sul modo in cui colleghi i dati agli elementi grafici. Vediamo ora un esempio completo di app con più classi per consolidare i concetti.
3. Esempio base completo di BaseAdapter Android Java con ListView
In questo esempio creiamo una semplice app che mostra una lista di frutti, ognuno con nome e un’icona. In particolare, useremo:
- Classe modello:
Frutto.java - Adapter personalizzato:
FruttoAdapter.java(con pattern ViewHolder) - Activity principale:
MainActivity.java - Layout XML dell’elemento:
item_frutto.xml - Layout XML dell’activity:
activity_main.xml
3.1 Modello Frutto.java
// Frutto.java
// Modello semplice con nome e id della risorsa immagine
public class Frutto {
private String nome;
private int iconaResId; // R.drawable.qualcosa
public Frutto(String nome, int iconaResId) {
this.nome = nome;
this.iconaResId = iconaResId;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public int getIconaResId() {
return iconaResId;
}
public void setIconaResId(int iconaResId) {
this.iconaResId = iconaResId;
}
}
3.2 Layout XML per ogni elemento: item_frutto.xml
Per esempio, si tratta di un layout composto da un’icona e un testo affiancati orizzontalmente.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp">
<ImageView
android:id="@+id/imageViewIcona"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="12dp"
android:contentDescription="@string/icona_frutto"
android:src="@drawable/ic_frutto_placeholder" />
<TextView
android:id="@+id/textViewNome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mela"
android:textSize="16sp" />
</LinearLayout>
3.3 Layout activity principale: activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<ListView
android:id="@+id/listViewFrutti"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
3.4 Adapter personalizzato BaseAdapter Android Java con ViewHolder

// FruttoAdapter.java
// Adapter personalizzato che estende BaseAdapter e usa il pattern ViewHolder
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class FruttoAdapter extends BaseAdapter {
private Context context;
private List<Frutto> listaFrutti;
private LayoutInflater inflater;
// Costruttore
public FruttoAdapter(Context context, List<Frutto> listaFrutti) {
this.context = context;
this.listaFrutti = listaFrutti;
this.inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
// Numero totale di elementi nella lista
return listaFrutti.size();
}
@Override
public Object getItem(int position) {
// Restituisce l'oggetto Frutto alla posizione specificata
return listaFrutti.get(position);
}
@Override
public long getItemId(int position) {
// In questo caso usiamo semplicemente la posizione come ID
return position;
}
// Classe ViewHolder per memorizzare i riferimenti alle viste
private static class ViewHolder {
ImageView imageViewIcona;
TextView textViewNome;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
// Non esiste una vista riutilizzabile, infliamo una nuova riga
convertView = inflater.inflate(R.layout.item_frutto, parent, false);
// Creiamo il ViewHolder e salviamo i riferimenti alle viste
holder = new ViewHolder();
holder.imageViewIcona = convertView.findViewById(R.id.imageViewIcona);
holder.textViewNome = convertView.findViewById(R.id.textViewNome);
// Associamo il ViewHolder alla vista
convertView.setTag(holder);
} else {
// Riutilizziamo il ViewHolder esistente
holder = (ViewHolder) convertView.getTag();
}
// Recuperiamo il frutto corrente
Frutto frutto = listaFrutti.get(position);
// Popoliamo le viste con i dati
holder.textViewNome.setText(frutto.getNome());
holder.imageViewIcona.setImageResource(frutto.getIconaResId());
return convertView;
}
}
3.5 Activity principale: MainActivity.java
// MainActivity.java
import android.os.Bundle;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView listViewFrutti;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listViewFrutti = findViewById(R.id.listViewFrutti);
// Creiamo una lista di frutti di esempio
List<Frutto> frutti = new ArrayList<>();
frutti.add(new Frutto("Mela", R.drawable.ic_mela));
frutti.add(new Frutto("Banana", R.drawable.ic_banana));
frutti.add(new Frutto("Arancia", R.drawable.ic_arancia));
frutti.add(new Frutto("Pera", R.drawable.ic_pera));
// Creiamo l'adapter e lo associamo alla ListView
FruttoAdapter adapter = new FruttoAdapter(this, frutti);
listViewFrutti.setAdapter(adapter);
}
}
4. Performance e pattern ViewHolder in BaseAdapter Android Java
Ad esempio, quando scorri una ListView, Android crea e distrugge molte viste. Se ad ogni passaggio chiami findViewById() per trovare i widget all’interno di ogni riga, il costo può diventare elevato e, di conseguenza, la lista può risultare scattosa.
Il pattern ViewHolder, invece, serve proprio a evitare chiamate ripetute a findViewById(). L’idea è:
- Creare una classe che contiene i riferimenti ai widget di una riga.
- Creare il ViewHolder solo quando
convertViewènull. - Salvare il ViewHolder nella vista tramite
setTag()e recuperarlo congetTag()quando la vista viene riutilizzata.
In questo modo, si riduce drasticamente il lavoro fatto durante lo scrolling e si migliora sensibilmente la fluidità.
Esempio di ViewHolder con BaseAdapter Android Java
private static class ViewHolder {
ImageView icona;
TextView titolo;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_layout, parent, false);
holder = new ViewHolder();
holder.icona = convertView.findViewById(R.id.imageViewIcona);
holder.titolo = convertView.findViewById(R.id.textViewTitolo);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Usa holder.icona e holder.titolo senza doverli cercare di nuovo
// ...
return convertView;
}
5. Mini App di esempio con BaseAdapter Android Java: Lista Contatti
Vediamo ora un esempio leggermente più completo: una lista di contatti con nome, numero di telefono e un’icona avatar. Inoltre, gestiremo anche il click sugli elementi mostrando un Toast con il nome del contatto selezionato.
5.1 Modello Contatto.java
// Contatto.java
public class Contatto {
private String nome;
private String numeroTelefono;
private int avatarResId;
public Contatto(String nome, String numeroTelefono, int avatarResId) {
this.nome = nome;
this.numeroTelefono = numeroTelefono;
this.avatarResId = avatarResId;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getNumeroTelefono() {
return numeroTelefono;
}
public void setNumeroTelefono(String numeroTelefono) {
this.numeroTelefono = numeroTelefono;
}
public int getAvatarResId() {
return avatarResId;
}
public void setAvatarResId(int avatarResId) {
this.avatarResId = avatarResId;
}
}
5.2 Layout XML dell’elemento: item_contatto.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/imageViewAvatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="12dp"
android:src="@drawable/ic_avatar_placeholder"
android:contentDescription="@string/avatar_contatto" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/textViewNomeContatto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mario Rossi"
android:textStyle="bold"
android:textSize="16sp" />
<TextView
android:id="@+id/textViewNumeroTelefono"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+39 333 1234567"
android:textSize="14sp"
android:textColor="#666666" />
</LinearLayout>
</LinearLayout>
5.3 Layout XML dell’activity: activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rubrica contatti"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginBottom="8dp" />
<ListView
android:id="@+id/listViewContatti"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="1dp" />
</LinearLayout>
5.4 ContattoAdapter.java: estendere BaseAdapter Android Java
// ContattoAdapter.java
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class ContattoAdapter extends BaseAdapter {
private Context context;
private List<Contatto> listaContatti;
private LayoutInflater inflater;
public ContattoAdapter(Context context, List<Contatto> listaContatti) {
this.context = context;
this.listaContatti = listaContatti;
this.inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return listaContatti.size();
}
@Override
public Object getItem(int position) {
return listaContatti.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
private static class ViewHolder {
ImageView imageViewAvatar;
TextView textViewNome;
TextView textViewNumero;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_contatto, parent, false);
holder = new ViewHolder();
holder.imageViewAvatar = convertView.findViewById(R.id.imageViewAvatar);
holder.textViewNome = convertView.findViewById(R.id.textViewNomeContatto);
holder.textViewNumero = convertView.findViewById(R.id.textViewNumeroTelefono);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Recupera il contatto corrente
Contatto contatto = listaContatti.get(position);
// Popola le viste
holder.textViewNome.setText(contatto.getNome());
holder.textViewNumero.setText(contatto.getNumeroTelefono());
holder.imageViewAvatar.setImageResource(contatto.getAvatarResId());
return convertView;
}
}
5.5 MainActivity.java con gestione dei click
// MainActivity.java
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView listViewContatti;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listViewContatti = findViewById(R.id.listViewContatti);
// Dati di esempio
final List<Contatto> contatti = new ArrayList<>();
contatti.add(new Contatto("Mario Rossi", "+39 333 1111111", R.drawable.ic_avatar_1));
contatti.add(new Contatto("Luca Bianchi", "+39 333 2222222", R.drawable.ic_avatar_2));
contatti.add(new Contatto("Anna Verdi", "+39 333 3333333", R.drawable.ic_avatar_3));
contatti.add(new Contatto("Giulia Neri", "+39 333 4444444", R.drawable.ic_avatar_4));
// Crea e assegna l'adapter
ContattoAdapter adapter = new ContattoAdapter(this, contatti);
listViewContatti.setAdapter(adapter);
// Gestione del click sugli elementi
listViewContatti.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Contatto contattoSelezionato = contatti.get(position);
String messaggio = "Hai selezionato: " + contattoSelezionato.getNome();
Toast.makeText(MainActivity.this, messaggio, Toast.LENGTH_SHORT).show();
}
});
}
}
6. BaseAdapter Android con più tipi di layout (getViewTypeCount e getItemViewType)
Un’altra esigenza frequente quando si lavora con BaseAdapter Android è gestire righe diverse nella stessa lista: ad esempio una riga di intestazione (header) e più righe di contenuto, oppure elementi normali e elementi in evidenza. Con ListView puoi farlo sovrascrivendo i metodi getViewTypeCount() e getItemViewType(int position).
// Esempio di BaseAdapter Android con due tipi di layout: HEADER e ITEM
public class SezioneAdapter extends BaseAdapter {
private static final int TIPO_HEADER = 0;
private static final int TIPO_ITEM = 1;
private LayoutInflater inflater;
private List<Object> elementi; // Può contenere sia String (header) che Prodotto (item)
public SezioneAdapter(Context context, List<Object> elementi) {
this.inflater = LayoutInflater.from(context);
this.elementi = elementi;
}
@Override
public int getCount() {
return elementi.size();
}
@Override
public Object getItem(int position) {
return elementi.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getViewTypeCount() {
// Abbiamo 2 tipi di vista: header e item normale
return 2;
}
@Override
public int getItemViewType(int position) {
Object obj = elementi.get(position);
if (obj instanceof String) {
return TIPO_HEADER; // Le stringhe rappresentano le intestazioni
} else {
return TIPO_ITEM; // Tutto il resto è un elemento normale
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int tipo = getItemViewType(position);
if (tipo == TIPO_HEADER) {
// Layout per l'intestazione
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_header, parent, false);
}
TextView textViewHeader = convertView.findViewById(R.id.textViewHeader);
String titoloSezione = (String) elementi.get(position);
textViewHeader.setText(titoloSezione);
} else {
// Layout per l'elemento normale
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_prodotto, parent, false);
holder = new ViewHolder();
holder.imageViewIcona = convertView.findViewById(R.id.imageViewIcona);
holder.textViewNome = convertView.findViewById(R.id.textViewNome);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Prodotto prodotto = (Prodotto) elementi.get(position);
holder.textViewNome.setText(prodotto.getNome());
holder.imageViewIcona.setImageResource(prodotto.getIconaResId());
}
return convertView;
}
// ViewHolder riutilizzato per il tipo ITEM
private static class ViewHolder {
ImageView imageViewIcona;
TextView textViewNome;
}
}
Grazie a questi due metodi, ListView sa quanti tipi diversi di riga esistono e può riciclare correttamente solo le viste compatibili. Se ti accorgi di avere molti tipi di layout diversi o logiche complesse, valuta comunque di migrare a RecyclerView, che gestisce meglio scenari avanzati.
7. Aggiornamento dinamico dei dati in BaseAdapter Android (notifyDataSetChanged)
Uno dei vantaggi di usare BaseAdapter Android è la possibilità di aggiornare dinamicamente il contenuto della lista quando cambiano i dati (ad esempio dopo una chiamata API o dopo un filtro di ricerca). Per fare questo, aggiorni la lista interna dell’adapter e poi chiami notifyDataSetChanged() per dire alla ListView di ridisegnarsi.
public class ProdottoAdapter extends BaseAdapter {
private List<Prodotto> prodotti;
private LayoutInflater inflater;
public ProdottoAdapter(Context context, List<Prodotto> prodotti) {
this.inflater = LayoutInflater.from(context);
this.prodotti = new ArrayList<>(prodotti); // Copia mutabile
}
// ... implementazioni di getCount(), getItem(), getItemId(), getView() ...
// Metodo per sostituire completamente la lista di dati
public void aggiornaProdotti(List<Prodotto> nuoviProdotti) {
this.prodotti.clear();
this.prodotti.addAll(nuoviProdotti);
// Notifica alla ListView che i dati sono cambiati
notifyDataSetChanged();
}
// Metodo per aggiungere un singolo elemento
public void aggiungiProdotto(Prodotto prodotto) {
this.prodotti.add(prodotto);
notifyDataSetChanged();
}
// Metodo per rimuovere un elemento
public void rimuoviProdotto(int position) {
if (position >= 0 && position < prodotti.size()) {
this.prodotti.remove(position);
notifyDataSetChanged();
}
}
}
In un’Activity o in un Fragment, ti basta conservare un riferimento all’adapter e chiamare questi metodi quando ricevi nuovi dati. Questo approccio è ideale per piccole liste; per dataset molto grandi o aggiornamenti frequenti, con RecyclerView è preferibile usare ListAdapter e DiffUtil.
8. BaseAdapter Android con checkbox e selezione multipla
Un caso pratico molto richiesto è la selezione multipla con checkbox, ad esempio per permettere all’utente di selezionare più elementi da una lista (file, contatti, prodotti). Con BaseAdapter Android puoi gestire facilmente questo scenario mantenendo una struttura dati che tiene traccia delle posizioni selezionate.
// Layout item_selezionabile.xml
// Contiene un TextView e un CheckBox affiancati
// Adapter con selezione multipla
public class SelezioneAdapter extends BaseAdapter {
private LayoutInflater inflater;
private List<String> elementi;
private SparseBooleanArray elementiSelezionati = new SparseBooleanArray();
public SelezioneAdapter(Context context, List<String> elementi) {
this.inflater = LayoutInflater.from(context);
this.elementi = elementi;
}
@Override
public int getCount() {
return elementi.size();
}
@Override
public Object getItem(int position) {
return elementi.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
private static class ViewHolder {
TextView textViewTitolo;
CheckBox checkBox;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_selezionabile, parent, false);
holder = new ViewHolder();
holder.textViewTitolo = convertView.findViewById(R.id.textViewTitolo);
holder.checkBox = convertView.findViewById(R.id.checkBoxSeleziona);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Imposta il testo
String titolo = elementi.get(position);
holder.textViewTitolo.setText(titolo);
// Imposta lo stato della checkbox in base alla posizione
boolean selezionato = elementiSelezionati.get(position, false);
holder.checkBox.setOnCheckedChangeListener(null); // Evita trigger indesiderati
holder.checkBox.setChecked(selezionato);
// Gestione del click sulla checkbox
holder.checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
elementiSelezionati.put(position, isChecked);
});
// Opzionale: gestire il click sull'intera riga
convertView.setOnClickListener(v -> {
boolean nuovoStato = !elementiSelezionati.get(position, false);
elementiSelezionati.put(position, nuovoStato);
notifyDataSetChanged();
});
return convertView;
}
// Restituisce la lista degli elementi selezionati
public List<String> getElementiSelezionati() {
List<String> selezionati = new ArrayList<>();
for (int i = 0; i < elementi.size(); i++) {
if (elementiSelezionati.get(i, false)) {
selezionati.add(elementi.get(i));
}
}
return selezionati;
}
}
Nell’Activity puoi quindi chiamare getElementiSelezionati() per recuperare tutti gli elementi marcati dall’utente. Fai solo attenzione a inizializzare sempre correttamente la checkbox in getView(), perché le viste vengono riciclate e potresti altrimenti vedere selezioni errate durante lo scroll.
9. Differenze tra BaseAdapter Android Java, ArrayAdapter e RecyclerView
La tabella seguente, infatti, riassume in modo sintetico le principali differenze tra queste tre soluzioni:
| Caratteristica | BaseAdapter + ListView | ArrayAdapter + ListView | RecyclerView |
|---|---|---|---|
| Flessibilità layout | Molto alta (layout completamente personalizzabile) | Media (ottimizzato per casi semplici) | Molto alta |
| Complessità di implementazione | Media | Bassa | Alta |
| Performance su liste molto lunghe | Buone con ViewHolder | Discrete | Eccellenti (riciclo avanzato) |
| Supporto funzioni avanzate (animazioni, grid, staggered) | Limitato | Limitato | Avanzato (LayoutManager, ItemDecoration, ecc.) |
| Uso consigliato nel 2024 | Progetti legacy, liste semplici, formazione | Liste molto semplici (stringhe, array) | Nuovi progetti, interfacce moderne |
7. Consigli pratici e best practice per BaseAdapter Android Java (2025)
- Per nuovi progetti complessi, preferisci
RecyclerView. Offre più controllo e integrazione con le librerie moderne (es. Paging, DiffUtil, ListAdapter). - Usa BaseAdapter quando devi mantenere codice esistente basato su
ListView, oppure per esercitarti a capire come funziona il binding dei dati alle viste. - Implementa sempre il pattern ViewHolder per evitare lag durante lo scroll.
- Evita logica pesante in getView(). Operazioni costose (IO, rete, parsing complesso) dovrebbero stare fuori dall’adapter.
- Gestisci il riciclo con attenzione: ricorda che la stessa vista può mostrare dati diversi durante lo scroll, quindi inizializza sempre tutti i campi (non dare per scontato lo stato precedente).
- Non fare assunzioni sulla posizione: i dati possono cambiare, quindi quando possibile lavora sugli ID o sugli oggetti, non su indici fissi.
- Se hai più tipi di vista (righe diverse nella stessa lista), valuta se passare a
RecyclerViewo, se resti conListView, sovrascrivigetItemViewType()egetViewTypeCount().
10. FAQ su BaseAdapter Android
Per chi sta iniziando a usare BaseAdapter Android, ecco alcune domande frequenti che aiutano a chiarire i dubbi più comuni.
- 1. Quando dovrei usare BaseAdapter invece di ArrayAdapter?
UsaArrayAdapterquando devi mostrare dati semplici (ad esempio solo testo) e ti basta un layout standard. Scegli BaseAdapter Android quando hai bisogno di layout personalizzati con più viste (immagini, pulsanti, checkbox), più tipi di riga o logiche di visualizzazione particolari. - 2. BaseAdapter è deprecato o ancora valido nel 2025?
BaseAdapternon è deprecato e continua a funzionare correttamente. Tuttavia, per i nuovi progetti Google consiglia di usareRecyclerView, che offre migliori performance, API più moderne e integrazione con librerie comeListAdapterePaging. - 3. Devo sempre usare il pattern ViewHolder con BaseAdapter Android?
Nella pratica, sì: il pattern ViewHolder è fondamentale per evitare chiamate ripetute afindViewById()dentrogetView(). Senza ViewHolder, le liste diventano facilmente lente e scattose, soprattutto su dispositivi meno recenti o con molte righe. - 4. Posso usare BaseAdapter con GridView o altre viste oltre a ListView?
Sì,BaseAdapterpuò essere usato anche conGridViewe con altre viste che accettano unListAdapter. Il principio è lo stesso: l’adapter trasforma i tuoi dati in viste da visualizzare nella griglia o nella lista. - 5. Come gestisco click e long-click sugli elementi con BaseAdapter Android?
Per la maggior parte dei casi puoi impostare unOnItemClickListenersullaListView(come mostrato nella mini app di esempio). Se invece ti servono interazioni su singoli widget dentro la riga (ad esempio un pulsante di cancellazione), puoi impostare i listener direttamente ingetView(), ricordandoti di usare la posizione o l’oggetto associato per capire quale elemento è stato toccato.
8. Conclusioni su BaseAdapter Android Java e risorse correlate
In conclusione, BaseAdapter Android Java rimane uno strumento utile per comprendere le basi del pattern adapter in Android e per gestire applicazioni legacy che usano ancora ListView. Sebbene oggi RecyclerView sia la scelta consigliata per nuove app e interfacce complesse, conoscere BaseAdapter Android Java ti aiuta comunque a capire meglio come funziona il riciclo delle viste e l’ottimizzazione delle performance.
A questo punto, ecco alcune risorse utili (in inglese):
Partendo dagli esempi di questa guida su BaseAdapter Android Java puoi adattare facilmente il codice ai tuoi modelli di dati e layout; inoltre, puoi sperimentare con diverse strutture e aggiungere funzionalità come menu contestuali, pulsanti di azione e caricamento asincrono delle immagini.
Articoli correlati
Guide correlate
Guide correlate
- Se stai lavorando con liste avanzate, approfondisci anche RecyclerView in Android per confrontarlo con BaseAdapter.
- Per gestire layout complessi in modo moderno, puoi leggere la guida su ConstraintLayout in Android.
- Se ti interessa personalizzare la barra superiore dell’app, dai un’occhiata alla guida su Toolbar in Android.
- Per creare menu laterali e navigazione a cassetto, puoi seguire la guida dedicata a NavigationDrawer in Android.
- Se vuoi animazioni fluide e transizioni tra viste, esplora la guida su MotionLayout in Android.
- Per implementare il gesto di trascinamento verso il basso per aggiornare i dati, puoi vedere la guida su SwipeRefreshLayout in Android.
- Se devi mostrare stati di caricamento e operazioni in corso, ti sarà utile la guida su ProgressBar in Android.
- Per una panoramica completa del percorso di studio, consulta anche la pagina hub Guide Android Java con tutte le risorse correlate.