Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 25 di 37
  • livello intermedio
Indice lezioni

Creazione di un stateful widget

Spesso un'app necessita di gestire dinamicamente modifiche a dati e alla UI. Per gestire queste necessità, Flutter richiede l'uso di stateful widget.
Spesso un'app necessita di gestire dinamicamente modifiche a dati e alla UI. Per gestire queste necessità, Flutter richiede l'uso di stateful widget.
Link copiato negli appunti

In una lezione precedente abbiamo parlato di Stateless e Stateful Widget come delle fondamenta di un’applicazione Flutter. In particolare, nel corso di queste lezioni ci siamo concentrati e abbiamo preso confidenza proprio con gli stateless widget, che sono perfetti per la creazione di componenti le cui proprietà sono immutabili. Infatti, l’unico modo per modificare questi widget, è la creazione di una nuova istanza.

Un’applicazione, però, non è mai del tutto statica e richiede comunque di:

  • tracciare i cambiamenti;
  • dare l’opportunità all’utente di poter interagire con la UI;
  • aggiornare la UI dinamicamente in caso di cambiamenti nelle informazioni mostrate.

Tutti aspetti, questi, che uno stateless widget non gestisce, ed è proprio in questo contesto che possono essere utilizzati gli stateful widget.

Questo tipo di widget fornisce sia delle configurazioni immutabili (come gli stateless widget) sia un oggetto che ne rappresenta lo stato e che può cambiare nel tempo, rappresentati dalle classi StatefulWidget e State rispettivamente. In particolare lo scopo dello State è quello di:

  • rappresentare lo stato dello stateful widget;
  • gestire le informazioni per interagire con questo in termini di comportamento e layout.

L’utilizzo di queste due classi è fondamentale a livello di performance in quanto, se da una parte abbiamo che gli StatefulWidget vengono distrutti e ricostruiti ad ogni cambio nelle configurazioni per apportare le modifiche alla UI, gli State widget, al contrario, continuano ad esistere e gestiscono le informazioni circa lo stato in cui si trova il widget. Questo comportamento porta ad importanti benefici a livello di performance e di costi computazionali.

In questa e nella prossima lezione vedremo in dettaglio le classi StatefulWidget e State e impareremo a creare uno nuovo stateful widget.

Le classi StatefulWidget e State

Vediamo a grandi linee i metodi e le proprietà offerte da queste classi entrando nel dettaglio del funzionamento del ciclo di vita dello State.

La classe StatefulWidget ha lo scopo di:

  • descrivere una porzione dell’UI mediante la definizione di altri widget in modo ricorsivo;
  • rilevare modifiche all’interfaccia a seguito di un’interazione.

Ad ogni modo, l’istanza stessa del widget è immutabile ma, a differenza della sua controparte stateless, gestisce uno stato mutabile rappresentato dalla classe State che resterà sempre lo stesso nonostante eventuali cambi di posizione nella struttura.

Di particolare interesse per noi sono i metodi offerti da questa classe, ossia:

Metodo Descrizione
createElement crea un nuovo StatefulElement nell’element tree per gestire la posizione corrente dello StatefulWidget nel widget tree. Questo metodo generalmente non viene mai sovrascritto da una sottoclasse che estende StatefulWidget
createState

crea lo stato mutabile (rappresentato da un nuovo oggetto State) per questo widget in una determinata posizione nella struttura.
Le sottoclassi devono sovrascrivere questo metodo per restituire un'istanza appena creata della sottoclasse dello State associata.
Questo metodo può essere invocato più volte dal framework durante il ciclo di vita dello SatefulWidget

La classe State gioca un ruolo fondamentale nella creazione degli stateful widget in quanto sono mutabili e riutilizzabili. In particolare un oggetto State:

  • può essere letto in modo asincrono;
  • potrebbe cambiare durante il ciclo di vita del widget a cui è associato;
  • deve essere avvisato quando avviene una modifica attraverso l’utilizzo del metodo State.setState.

Vediamo quindi le sue tre proprietà fondamentali e capiamone il funzionamento.

Proprietà Tipo Accettato Descrizione
context BuildContext rappresenta la posizione nel widget tree in cui viene creato il widget associato allo stato. In particolare, il framework assocerà in modo permanente il BuildContext allo State dopo l’invocazione del metodo StatefulWidget.createState e prima dell’invocazione dell’initSate
mounted bool attraverso questo valore booleano il framework è in grado di sapere se lo State è montato o meno. Lo State risulta montato quando ha associato un BuildContext e resterà in questo stato finché non verrà invocato il metodo dispose
widget T rappresenta l'attuale configurazione dello State, ossia l'istanza dello StatefulWidget corrispondente. Questa proprietà è inizializzata dal framework prima di chiamare initState. Se viene aggiornata la configurazione dello stateful widget, verrà creato un nuovo widget con lo stesso runtimeType e Widget.key dello stateful widget corrente.
Il nuovo widget verrà quindi impostato come valore di questa proprietà attraverso l’invocazione del metodo didUpdateWidget avente in input la vecchia istanza

Concentriamoci adesso sui metodi offerti da questa classe che ne definiscono il ciclo di vita.

Metodo Descrizione
build(BuildContext context) descrive la parte di UI rappresentata dallo stateful widget e quindi si occupa di creare l’interfaccia utente a differenza di quanto visto e fatto con uno stateless widget.
Questo metodo può essere invocato dal framework:

  • dopo aver invocato il metodo initState;
  • dopo aver invocato il metodo didUpdateWidget;
  • dopo aver ricevuto l’invocazione di setState;
  • dopo che è cambiata una dipendenza dell’oggetto State;
  • dopo aver invocato il metodo deactivate e aver successivamente reinserito l'oggetto State nell'albero in un'altra posizione
deactivate() viene invocato dal framework quando lo State deve essere rimosso dall’element tree a cui è associato
didChangeDependencies() viene invocato quando viene modificata una dipendenza dello State
didUpdateWidget(covariant T oldWidget) viene invocato ogni volta che cambiano le configurazioni del widget. In particolare, quando il widget padre viene ricostruito e richiede la ricreazione dello stateful widget (nella medesima posizione nell’albero e con lo stesso runtimeType e Widget.key), il framework aggiornerà la proprietà State.widget aggiornando il riferimento al nuovo widget creato
dispose() è invocato quando lo State deve essere rimosso in modo permanente. Una volta invocato, lo State è considerato smontato dal framework e non potrà più essere rimontato. In questo caso la proprietà mounted viene impostata a false
initState() viene invocato quando lo State viene inserito nel widget tree. In particolare, il framework invocherà questo metodo esattamente una volta per ogni State che deve creare
setState(VoidCallback fn) notifica il framework che lo stato interno dello State è cambiato

Vediamo come vengono impiegati questi metodi dal framework per gestire il ciclo di vita di un oggetto State e dell’element tree associato:

  • il framework crea uno nuovo oggetto State a seguito dell’invocazione del metodo StatefulWidget.createState;
  • l’oggetto State creato viene associato al BuildContext in modo permanente e può essere considerato montato, quindi la proprietà mounted è impostata a true;
  • il framework invoca il metodo initState;
  • il framework invoca il metodo didChangeDependencies che verrà invocato ogni volta che i widget del sottoalbero vengono modificati o il widget a cui lo stato fa riferimento si sposta nella struttura;
  • a questo punto lo State è correttamente inizializzato e il suo metodo build può essere invocato dal framework in qualsiasi momento. L’invocazione del metodo build può inoltre essere forzata attraverso l’invocazione del metodo setState;
  • da questo momento in poi, se il widget padre viene ricreato e richiede l’aggiornamento del sottoalbero, questo verrà distrutto e ricreato con un nuovo sottoalbero avente lo stesso runtimeType and Widget.key del precedente. Quando ciò accade, il framework aggiornerà la proprietà State.widget con il riferimento al nuovo widget creato e invocherà il metodo didUpdateWidget;
  • quando il sottoalbero contenente lo State è rimosso dall’albero, il framework invoca il metodo deactivate e può:
    • reinserire il sottoalbero in un altro punto dell’albero invocando il metodo State.build per dare allo State la possibilità di adattarsi alla sua nuova posizione nella struttura;
    • invocare il metodo dispose per indicare che il sottoalbero e il relativo oggetto State non verranno più ricostruiti. Una volta invocato, lo State è considerato unmounted e la proprietà mounted viene impostata a false. In questo caso, non sarà più possibile rimontare lo State.

Come si può evincere, gran parte dei metodi definiti per la classe State sono direttamente utilizzati dal framework ed è incredibilmente raro doverli sovrascrivere o invocarli.

Per ulteriori informazioni si rimanda alla documentazione ufficiale di queste classi.

Ti consigliamo anche