I Fragment costituiscono senz'altro uno dei più importanti elementi per la creazione di una interfaccia utente Android moderna. Il loro ruolo a partire da Android 3.0 è diventato preponderante tanto che ormai rappresentano una delle conoscenze più importanti per il programmatore.
Un Fragment è una porzione di Activity. Ma si faccia attenzione a comprenderne bene il ruolo. Non si tratta solo di un gruppo di controlli o di una sezione del layout. Può essere definito più come una specie di sub-activity con un suo ruolo funzionale molto importante ed un suo ciclo di vita.
Fragments e Activity
Definiamo subito il rapporto tra Fragments e Activity.
Prima di tutto un Fragment non può vivere senza un'Actvity. Tipicamente nei nostri programmi creeremo più Fragments che si alterneranno nel layout mentre di Activity ne sarà sufficiente una (ma possono essere anche di più).
Come detto il Fragment ha il suo ciclo di vita fortemente collegato con quello dell'Activity di appartenenza.
La figura qui riportata mostra la sequenza di stati che scandiscono la vita del Fragment.
Come si vede ricordano molto quelli dell'Activity.
La fase più variegata è l'inizializzazione del fragment:
- onAttach: segnala il momento in cui il Fragment scopre l'Activity di appartenenza. Attenzione che a quel punto l'Activity non è stata ancora creata quindi si può solo conservare un riferimento ad essa ma non interagirvi;
- onCreate: è la creazione del Fragment in quanto componente;
- onCreateView: il programmatore vi lavorerà spesso. È il momento in cui viene creato il layout del Fragment. Solitamente qui si fa uso del LayoutInflater;
- onActivityCreated: segnala che la creazione dell'Activity è stata completata, vi si può interagire in tutto e per tutto.
Gli altri metodi di callback del ciclo di vita vengono chiamati in corrispondenza degli omonimi metodi dell'Activity.
Hello Fragment!
Come abbiamo fatto per le Activity, anche per i Fragment inizieremo con un “Hello World”. In questo caso, lo scopo dell'esempio non sarà, ovviamente, tanto l'apparizione del messaggio di saluto quanto osservare le fasi che portano alla creazione di un Fragment e del suo innesto all'interno di un layout.
Per raggiungere lo scopo, seguiremo questi step che tratteranno sia XML, i primi due, che Java, i secondi due :
- creeremo il layout per l'Activity in cui ricaveremo il posto per alloggiare il nostro Fragment;
- definiremo il layout del Fragment che conterrà il vero aspetto dell'Activity e, di conseguenza, anche la stringa “Hello World”;
- definiremo la classe Fragment che essenzialmente servirà a caricare il layout di cui al punto precedente;
- creeremo la nostra Activity che svolgerà per lo più il ruolo di bacino di Fragment.
Il primo frammento di codice mostra il layout del Fragment (file: res/layout/fragment_main.xml).
Come si vede, se fosse stato destinato ad un'Activity sarebbe stato identico. Quindi la novità architetturale dei Fragment non influenza il layout.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
Il layout dell'Activity è il seguente (file: res/layout/activity_main.xml):
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Tutto lo spazio disponibile verrà riempito da un layout che non abbiamo mai usato sinora: il FrameLayout.
Viene utilizzato quando vi si deve ospitare un unico elemento, in questo caso il Fragment. Fondamentale definire l'id in quanto questo Layout svolgerà il ruolo di contenitore del Fragment e pertanto verrà invocato dal codice Java.
La classe HelloFragment mostra alcune evidenti caratteristiche:
- estende la classe Fragment del framework. Si noti che, negli anni, i programmatori hanno dovuto porre particolare
attenzione a quale classe Fragment utilizzare nel rispetto delle problematiche di compatibilità tra le varie versioni del sistema. Oggigiorno,
a seguito della riorganizzazione delle API Android, impiegheremo la classe appartenente al packageandroidx.fragment.app
; - presenta metodi propri del ciclo di vita dei Fragment. Come già accennato, sarà frequente l'ovverride del metodo
onCreateView
in quanto è il momento in cui viene allestita l'interfaccia utente mostrata dal Fragment. Non ci sorprendono (ormai) le operazioni svolte al suo interno: assegnazione di un Layout mediante LayoutInflater.
public class HelloFragment extends Fragment
{
public HelloFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
Il codice dell'Activity contiene solo il metodo onCreate
. Al suo interno, vengono svolte nelle prime due righe le operazioni consuete ma questa volta il caricamento del layout con setContentView
non basta. Infatti questo porterà a display solo il FrameLayout ancora vuoto.
Per aggiungere il Fragment, si procederà per via dinamica richiedendo al FragmentManager l'avvio di una transazione add
che aggiungerà il nuovo Fragment di classe HelloFragment al layout identificato da R.id.container
.
public class MainActivity extends AppCompatActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null)
{
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new HelloFragment()).commit();
}
}
}
L'operazione add
fa parte delle FragmentTransactions. Le useremo anche nel prossimo capitolo ma intanto si pensi ad esse come delle operazioni che devono essere svolte dal FragmentManager sui Fragments amministrati.
Le FragmentTransactions più comuni sono:
add |
Aggiunge un Fragment all'Activity |
remove |
Rimuove un fragment precedentemente aggiunto |
replace |
Sostituisce un Fragment con un altro |
hide |
Nasconde un fragment |
show |
Mostra un fragment precedentemente nascosto |
Argomenti e dettagli ulteriori sono disponibili a sufficienza nella documentazione ufficiale.
Notare ancora che, come avviene per le transazioni nei database, le operazioni iniziano con un beginTransaction
e vengono definitivamente salvate con un commit
. Si può sperimentare l'uso dei Fragment realizzando layout basati su strutture a tab e a schede, molto comuni nelle interfacce utente: spieghiamo tutto ciò nell'esempio proposto all'interno della nostra guida di approfondimento.