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.
Sfida
MedioSalva 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)),
],
),
),
);
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Dati e rete
3Quando le chiamate falliscono
Gestire gli errori con tryLanciare un errorePulire con finallyLo stato di errore di FutureBuilderUn pulsante per riprovareEsercitati da solo: Compilatore Flutter online