Se ti stai chiedendo come funziona BaseAdapter Android Java e quando ha senso usarlo, questa guida pratica ti accompagna passo passo nella creazione di liste personalizzate e performanti. Inoltre, scoprirai in modo chiaro cos’è questa classe, perché è diversa da ArrayAdapter e RecyclerView e come integrarla correttamente nella tua app. In particolare, tutti gli esempi sono scritti in Java e pensati per essere usati subito in Android Studio, così puoi copiare, adattare e testare il codice nel tuo progetto in modo immediato. In conclusione, continua a leggere per capire davvero come sfruttare BaseAdapter al meglio nei tuoi layout con ListView.
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.
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. Pattern ViewHolder in BaseAdapter Android Java: perché è importante
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. 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().
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.