[{"data":1,"prerenderedAt":75},["ShallowReactive",2],{"tutorial-gestire-il-ciclo-di-vita-dei-widget-in-flutter-con-statefulwidget-e-mixin":3,"comments-tutorial-gestire-il-ciclo-di-vita-dei-widget-in-flutter-con-statefulwidget-e-mixin":74},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"video_url":10,"difficulty":11,"estimated_minutes":12,"flutter_version":13,"status":14,"published_at":15,"meta_title":16,"meta_description":17,"category":18,"author":22,"steps":25},47,"Gestire il ciclo di vita dei widget in Flutter con StatefulWidget e mixin","gestire-il-ciclo-di-vita-dei-widget-in-flutter-con-statefulwidget-e-mixin","Impara a padroneggiare il ciclo di vita di uno StatefulWidget in Flutter: da initState a dispose, fino ai mixin come WidgetsBindingObserver per reagire allo stato dell'app.","Comprendere il ciclo di vita dei widget è fondamentale per scrivere app Flutter robuste ed efficienti. Ogni `StatefulWidget` attraversa una serie di fasi ben definite, dalla creazione dello stato alla sua distruzione. Sapere *quando* e *dove* eseguire operazioni come inizializzare controller, sottoscrivere stream o liberare risorse evita memory leak e comportamenti imprevisti.\n\nIn questo tutorial vedremo passo dopo passo tutti i metodi del ciclo di vita di uno `State`, quando vengono chiamati e a cosa servono. Aggiungeremo poi il mixin `WidgetsBindingObserver` per intercettare i cambi di stato dell'intera applicazione (foreground, background, chiusura). Al termine avrai un modello mentale chiaro per gestire correttamente le risorse nei tuoi widget.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F9f0977c7-5756-482d-84f6-8c5d1d0ebbb5.jpg",null,"intermediate",35,"3.x","published","2026-07-24T04:30:51+00:00","Ciclo di vita dei widget in Flutter: guida completa","Guida pratica al ciclo di vita di StatefulWidget in Flutter: initState, didChangeDependencies, dispose e il mixin WidgetsBindingObserver.",{"id":19,"name":20,"slug":21},3,"Best practice","best-practice",{"id":23,"name":24},1,"Flutter Bot",[26,33,40,46,53,60,67],{"id":27,"position":23,"title":28,"body":29,"code_snippet":30,"code_language":31,"expected_result":32,"demo_url":10,"video_url":10},316,"Creare uno StatefulWidget di base","Partiamo creando un semplice `StatefulWidget`. Ricorda che un `StatefulWidget` è composto da due classi: il widget stesso (immutabile) e la sua classe `State` (mutabile), che contiene lo stato e la logica del ciclo di vita.\n\nIl metodo `createState()` viene chiamato una sola volta da Flutter quando il widget viene inserito nell'albero per la prima volta.","import 'package:flutter\u002Fmaterial.dart';\n\nclass LifecycleDemo extends StatefulWidget {\n  const LifecycleDemo({super.key, required this.title});\n\n  final String title;\n\n  @override\n  State\u003CLifecycleDemo> createState() => _LifecycleDemoState();\n}\n\nclass _LifecycleDemoState extends State\u003CLifecycleDemo> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: Text(widget.title)),\n      body: const Center(child: Text('Ciclo di vita')),\n    );\n  }\n}","dart","Una schermata con AppBar e testo centrato. Il metodo build viene eseguito ogni volta che il widget deve essere ridisegnato.",{"id":34,"position":35,"title":36,"body":37,"code_snippet":38,"code_language":31,"expected_result":39,"demo_url":10,"video_url":10},317,2,"Inizializzare risorse con initState","`initState()` viene chiamato **una sola volta**, subito dopo la creazione dell'oggetto `State` e prima del primo `build`. È il posto giusto per inizializzare controller, timer, animazioni o sottoscrivere stream.\n\n**Regola d'oro**: chiama sempre `super.initState()` come prima istruzione. Non puoi ancora accedere in modo sicuro a `InheritedWidget` (come `Theme.of` o `MediaQuery.of`) qui: per quello esiste `didChangeDependencies`.","class _LifecycleDemoState extends State\u003CLifecycleDemo> {\n  late final TextEditingController _controller;\n  int _rebuildCount = 0;\n\n  @override\n  void initState() {\n    super.initState();\n    debugPrint('initState: creo le risorse');\n    _controller = TextEditingController();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    _rebuildCount++;\n    return Scaffold(\n      appBar: AppBar(title: Text(widget.title)),\n      body: Padding(\n        padding: const EdgeInsets.all(16),\n        child: Column(\n          children: [\n            TextField(controller: _controller),\n            Text('Build eseguiti: $_rebuildCount'),\n          ],\n        ),\n      ),\n    );\n  }\n}","Nella console appare 'initState: creo le risorse' una sola volta all'apertura della schermata.",{"id":41,"position":19,"title":42,"body":43,"code_snippet":44,"code_language":31,"expected_result":45,"demo_url":10,"video_url":10},318,"Reagire ai cambi di dipendenze con didChangeDependencies","`didChangeDependencies()` viene chiamato subito dopo `initState` (al primo caricamento) e ogni volta che cambia un `InheritedWidget` da cui il widget dipende (ad esempio quando cambia il tema o la lingua).\n\nÈ il punto corretto per leggere valori da `Theme.of(context)`, `MediaQuery.of(context)` o provider ereditati, perché qui il `context` è pienamente disponibile.","@override\nvoid didChangeDependencies() {\n  super.didChangeDependencies();\n  final brightness = Theme.of(context).brightness;\n  debugPrint('didChangeDependencies: brightness = $brightness');\n}","Il log stampa la brightness corrente all'avvio e di nuovo se il tema dell'app cambia (es. passaggio a dark mode).",{"id":47,"position":48,"title":49,"body":50,"code_snippet":51,"code_language":31,"expected_result":52,"demo_url":10,"video_url":10},319,4,"Gestire l'aggiornamento del widget con didUpdateWidget","Quando il widget padre si ricostruisce con nuovi parametri, Flutter riutilizza lo stesso oggetto `State` ma sostituisce l'istanza del widget. `didUpdateWidget(oldWidget)` ti permette di confrontare i vecchi valori con quelli nuovi (accessibili tramite `widget`) e reagire di conseguenza, ad esempio ricreando un controller basato su una proprietà cambiata.","@override\nvoid didUpdateWidget(covariant LifecycleDemo oldWidget) {\n  super.didUpdateWidget(oldWidget);\n  if (oldWidget.title != widget.title) {\n    debugPrint('Titolo cambiato: ${oldWidget.title} -> ${widget.title}');\n  }\n}","Se il widget padre passa un nuovo titolo, viene stampato il confronto tra vecchio e nuovo valore senza ricreare lo State.",{"id":54,"position":55,"title":56,"body":57,"code_snippet":58,"code_language":31,"expected_result":59,"demo_url":10,"video_url":10},320,5,"Liberare le risorse con dispose","`dispose()` viene chiamato **una sola volta** quando l'oggetto `State` viene rimosso permanentemente dall'albero. È fondamentale liberare qui tutte le risorse allocate in `initState`: controller, stream subscription, timer, animazioni.\n\nDimenticare `dispose` è una delle cause più comuni di memory leak in Flutter. Chiama `super.dispose()` come **ultima** istruzione.","@override\nvoid dispose() {\n  debugPrint('dispose: libero le risorse');\n  _controller.dispose();\n  super.dispose();\n}","Uscendo dalla schermata viene stampato 'dispose: libero le risorse' e il TextEditingController viene distrutto correttamente.",{"id":61,"position":62,"title":63,"body":64,"code_snippet":65,"code_language":31,"expected_result":66,"demo_url":10,"video_url":10},321,6,"Intercettare lo stato dell'app con WidgetsBindingObserver","Oltre al ciclo di vita del singolo widget, spesso serve reagire ai cambi di stato dell'intera applicazione (l'utente la mette in background, torna in foreground, la chiude). Il mixin `WidgetsBindingObserver` con l'override di `didChangeAppLifecycleState` permette proprio questo.\n\nRicorda di registrare l'observer in `initState` e di rimuoverlo in `dispose` per evitare leak.","class _LifecycleDemoState extends State\u003CLifecycleDemo>\n    with WidgetsBindingObserver {\n  @override\n  void initState() {\n    super.initState();\n    WidgetsBinding.instance.addObserver(this);\n  }\n\n  @override\n  void didChangeAppLifecycleState(AppLifecycleState state) {\n    super.didChangeAppLifecycleState(state);\n    switch (state) {\n      case AppLifecycleState.resumed:\n        debugPrint('App in primo piano');\n      case AppLifecycleState.inactive:\n        debugPrint('App inattiva');\n      case AppLifecycleState.paused:\n        debugPrint('App in background');\n      case AppLifecycleState.detached:\n        debugPrint('App in chiusura');\n      case AppLifecycleState.hidden:\n        debugPrint('App nascosta');\n    }\n  }\n\n  @override\n  void dispose() {\n    WidgetsBinding.instance.removeObserver(this);\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) => const SizedBox.shrink();\n}","Mettendo l'app in background o riportandola in primo piano, la console mostra i relativi messaggi di stato del ciclo di vita dell'applicazione.",{"id":68,"position":69,"title":70,"body":71,"code_snippet":72,"code_language":31,"expected_result":73,"demo_url":10,"video_url":10},322,7,"Riepilogo dell'ordine di esecuzione","Ora hai il quadro completo. L'ordine tipico dei metodi è:\n\n1. **createState()** → crea l'oggetto State\n2. **initState()** → una volta, inizializza risorse\n3. **didChangeDependencies()** → dopo initState e ai cambi di InheritedWidget\n4. **build()** → ogni volta che serve ridisegnare\n5. **didUpdateWidget()** → quando il padre passa nuovi parametri\n6. **dispose()** → una volta, alla rimozione\n\n**Best practice da ricordare:**\n\n- Alloca risorse in `initState`, liberale in `dispose`.\n- Non chiamare `setState` dentro `build` o `dispose`.\n- Usa `didChangeDependencies` per leggere `Theme`, `MediaQuery`, provider.\n- Registra\u002Frimuovi sempre gli observer in modo simmetrico.\n- Per operazioni asincrone in `initState`, controlla `mounted` prima di chiamare `setState`.","\u002F\u002F Esempio: async in initState con controllo di mounted\n@override\nvoid initState() {\n  super.initState();\n  _caricaDati();\n}\n\nFuture\u003Cvoid> _caricaDati() async {\n  final dati = await Future.delayed(\n    const Duration(seconds: 1),\n    () => 'Caricato',\n  );\n  if (!mounted) return; \u002F\u002F evita setState su widget rimosso\n  setState(() {\n    \u002F\u002F aggiorna lo stato con i dati\n  });\n}","Hai un modello mentale completo del ciclo di vita e sai come gestire operazioni asincrone in sicurezza controllando la proprietà mounted.",[],1785219597827]