Menu
CoddyTech

Pulire con finally

Fa parte della sezione Dati e rete del percorso Flutter di Coddy. Lezione 12 di 27.

Alcune operazioni devono essere eseguite sia che una chiamata abbia avuto successo sia che sia fallita: nascondere la rotellina di caricamento, riattivare un pulsante. Scriverle sia in try sia in catch rende facile dimenticarsene in uno dei due blocchi. Dart ha un terzo blocco per questo, finally:

try {
  await saveName(name);
} catch (e) {
  // mostra l'errore
} finally {
  // viene sempre eseguito: dopo try o dopo catch
}

finally viene eseguito per ultimo, ogni volta: dopo try se ha avuto successo, dopo catch se è fallito. Questo lo rende il posto giusto per annullare ciò che hai predisposto prima della chiamata.

Qui l'app disattiva Save mentre salva, con onPressed: saving ? null : save. Non è possibile premere un pulsante il cui onPressed è null. Se saving non torna mai a false, il pulsante rimane disattivato per sempre.

challenge icon

Sfida

Medio

Salva con un campo vuoto: viene visualizzato l'errore e Salva rimane grigio, quindi non puoi più riprovare. Sposta saving = false fuori dal blocco try e inseriscilo in un blocco finally, all'interno di un proprio setState.

Provalo tu

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: NameScreen(),
    );
  }
}

class NameScreen extends StatefulWidget {
  const NameScreen({super.key});

  @override
  State<NameScreen> createState() => _NameScreenState();
}

class _NameScreenState extends State<NameScreen> {
  final controller = TextEditingController();
  String status = '';
  bool saving = false;

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  Future<void> saveName(String name) async {
    await Future.delayed(const Duration(seconds: 1));
    if (name.isEmpty) {
      throw Exception('The name cannot be empty');
    }
  }

  Future<void> save() async {
    setState(() {
      saving = true;
    });
    try {
      await saveName(controller.text);
      setState(() {
        status = 'Saved: ${controller.text}';
        saving = false;
      });
    } catch (e) {
      setState(() {
        status = '$e';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: controller,
              decoration: const InputDecoration(labelText: 'Name'),
            ),
            const SizedBox(height: 16),
            ElevatedButton(onPressed: saving ? null : save, child: const Text('Save')),
            const SizedBox(height: 16),
            Text(status, style: const TextStyle(fontSize: 18)),
          ],
        ),
      ),
    );
  }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Dati e rete

Esercitati da solo: Compilatore Flutter online