[{"data":1,"prerenderedAt":22},["ShallowReactive",2],{"articolo-gestire-il-ciclo-di-vita-dellapp-in-flutter-con-applifecyclelistener":3,"comments-article-gestire-il-ciclo-di-vita-dellapp-in-flutter-con-applifecyclelistener":21},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"video_url":10,"status":11,"published_at":12,"meta_title":13,"meta_description":14,"category":15,"author":19},44,"Gestire il ciclo di vita dell'app in Flutter con AppLifecycleListener","gestire-il-ciclo-di-vita-dellapp-in-flutter-con-applifecyclelistener","Impara a intercettare i cambi di stato dell'applicazione (foreground, background, chiusura) con la nuova API AppLifecycleListener introdotta in Flutter 3.13, per salvare dati e gestire risorse in modo affidabile.","## Perché il ciclo di vita conta\n\nOgni app mobile attraversa continuamente diversi stati: viene messa in background quando l'utente riceve una telefonata, torna in foreground quando riprende l'attività, oppure viene chiusa del tutto. Reagire correttamente a questi eventi è fondamentale per salvare lo stato dell'utente, mettere in pausa animazioni o video, liberare risorse e gestire le connessioni di rete.\n\nStoricamente in Flutter si usava `WidgetsBindingObserver` con il metodo `didChangeAppLifecycleState`. A partire da **Flutter 3.13** è disponibile un'API dedicata e più espressiva: `AppLifecycleListener`, che offre callback granulari per ogni transizione di stato.\n\n## Gli stati del ciclo di vita\n\nL'enum `AppLifecycleState` prevede i seguenti valori:\n\n- **resumed**: l'app è visibile e riceve input dall'utente.\n- **inactive**: l'app è visibile ma non riceve input (es. durante una chiamata in arrivo o lo split-screen).\n- **hidden**: l'app non è più visibile (stato introdotto per uniformare il comportamento tra piattaforme).\n- **paused**: l'app è in background e non visibile.\n- **detached**: l'app è ancora ospitata dall'engine ma senza view collegate; tipico durante l'avvio o la chiusura.\n\nLe transizioni seguono un percorso ben definito. Passando in background l'ordine è: `resumed → inactive → hidden → paused`. Al ritorno in foreground il percorso è inverso.\n\n## L'approccio classico con WidgetsBindingObserver\n\nPrima di vedere la nuova API, ecco il metodo tradizionale, ancora perfettamente valido:\n\n```dart\nclass _HomePageState extends State\u003CHomePage>\n    with WidgetsBindingObserver {\n  @override\n  void initState() {\n    super.initState();\n    WidgetsBinding.instance.addObserver(this);\n  }\n\n  @override\n  void dispose() {\n    WidgetsBinding.instance.removeObserver(this);\n    super.dispose();\n  }\n\n  @override\n  void didChangeAppLifecycleState(AppLifecycleState state) {\n    if (state == AppLifecycleState.paused) {\n      \u002F\u002F Salva lo stato dell'utente\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) => const Scaffold();\n}\n```\n\nQuesto approccio funziona, ma costringe a un unico metodo `didChangeAppLifecycleState` in cui gestire tutti i casi con una serie di `if`.\n\n## La nuova API: AppLifecycleListener\n\n`AppLifecycleListener` espone callback separate per ogni transizione, rendendo il codice più leggibile:\n\n```dart\nimport 'package:flutter\u002Fwidgets.dart';\n\nclass LifecycleManager {\n  late final AppLifecycleListener _listener;\n\n  void init() {\n    _listener = AppLifecycleListener(\n      onResume: () => debugPrint('App tornata in primo piano'),\n      onInactive: () => debugPrint('App inattiva'),\n      onHide: () => debugPrint('App nascosta'),\n      onPause: () => debugPrint('App in background'),\n      onDetach: () => debugPrint('App scollegata'),\n      onShow: () => debugPrint('App di nuovo visibile'),\n      onStateChange: (state) => debugPrint('Nuovo stato: $state'),\n    );\n  }\n\n  void dispose() {\n    _listener.dispose();\n  }\n}\n```\n\nÈ importante chiamare sempre `dispose()` sul listener per evitare memory leak.\n\n## Intercettare la richiesta di chiusura\n\nUna delle funzionalità più interessanti è `onExitRequested`, che permette di intercettare la richiesta di chiusura dell'app (principalmente su desktop) e decidere se consentirla o annullarla, ad esempio per mostrare un dialog di conferma:\n\n```dart\n_listener = AppLifecycleListener(\n  onExitRequested: () async {\n    final shouldExit = await _mostraDialogConferma();\n    return shouldExit\n        ? AppExitResponse.exit\n        : AppExitResponse.cancel;\n  },\n);\n```\n\nQuesto è utilissimo per app che devono salvare lavoro non completato prima di chiudersi.\n\n## Esempio pratico in un widget\n\nEcco come integrare `AppLifecycleListener` in uno `StatefulWidget` per mettere in pausa un video quando l'app va in background:\n\n```dart\nclass VideoScreen extends StatefulWidget {\n  const VideoScreen({super.key});\n\n  @override\n  State\u003CVideoScreen> createState() => _VideoScreenState();\n}\n\nclass _VideoScreenState extends State\u003CVideoScreen> {\n  late final AppLifecycleListener _listener;\n\n  @override\n  void initState() {\n    super.initState();\n    _listener = AppLifecycleListener(\n      onPause: _pausaVideo,\n      onResume: _riprendiVideo,\n    );\n  }\n\n  void _pausaVideo() {\n    \u002F\u002F controller.pause();\n  }\n\n  void _riprendiVideo() {\n    \u002F\u002F controller.play();\n  }\n\n  @override\n  void dispose() {\n    _listener.dispose();\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) => const Scaffold();\n}\n```\n\n## Differenze tra piattaforme\n\nÈ bene ricordare alcune particolarità:\n\n- Su **iOS** lo stato `detached` può non essere sempre emesso alla chiusura, perché il sistema può terminare il processo bruscamente.\n- `onExitRequested` è rilevante soprattutto su **desktop** (Windows, macOS, Linux) e sul web; su mobile la chiusura è gestita diversamente dal sistema operativo.\n- Lo stato `hidden` è stato aggiunto per uniformare il comportamento: prima non tutte le piattaforme lo emettevano.\n\n## Best practice\n\n- **Salva sempre lo stato critico** in `onPause` (o `paused`), non affidarti a `detached`, che non è garantito.\n- **Rilascia le risorse pesanti** (camera, microfono, connessioni) quando l'app passa in background per rispettare i limiti del sistema.\n- **Non eseguire operazioni lunghe** nelle callback: lo stato può cambiare rapidamente.\n- **Usa `onStateChange`** solo quando ti serve una logica trasversale a più stati, altrimenti preferisci le callback specifiche.\n\n## Conclusione\n\n`AppLifecycleListener` rappresenta un'evoluzione naturale rispetto a `WidgetsBindingObserver`: offre un'API più chiara, callback dedicate e la possibilità di intercettare la chiusura dell'app. Integrarlo nelle proprie app significa gestire in modo affidabile il salvataggio dei dati e le risorse, migliorando l'esperienza utente su tutte le piattaforme.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002F1dbd544b-e229-406a-90a9-0ccdc4651960.jpg",null,"published","2026-07-18T04:00:41+00:00","Ciclo di vita app Flutter con AppLifecycleListener","Guida pratica ad AppLifecycleListener in Flutter: intercetta foreground, background e chiusura dell'app per salvare dati e gestire risorse.",{"id":16,"name":17,"slug":18},1,"Guide","guide",{"id":16,"name":20},"Flutter Bot",[],1785219600660]