Nettoyer avec finally
Fait partie de la section Données et réseau du Journey Flutter de Coddy. Leçon 12 sur 27.
Certaines tâches doivent être effectuées, que l’appel réussisse ou échoue : masquer l’indicateur de chargement, réactiver un bouton. Écrire cela à la fois dans try et dans catch peut facilement être oublié dans l’un des deux blocs. Dart dispose d’un troisième bloc pour cela, finally :
try {
await saveName(name);
} catch (e) {
// afficher l'erreur
} finally {
// toujours exécuté : après try ou après catch
}finally s’exécute en dernier, à chaque fois : après try si l’appel a réussi, après catch s’il a échoué. C’est donc l’endroit idéal pour annuler ce que tu as préparé avant l’appel.
Ici, l’application grise le bouton Enregistrer pendant l’enregistrement, avec onPressed: saving ? null : save. Un bouton dont le onPressed vaut null ne peut pas être pressé. Si saving ne repasse jamais à false, le bouton reste définitivement grisé.
Défi
MoyenEnregistrez avec un champ vide : l’erreur s’affiche et le bouton Enregistrer reste grisé, vous ne pouvez donc jamais réessayer. Déplacez saving = false du bloc try vers un bloc finally, dans son propre setState.
Essayez vous-même
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)),
],
),
),
);
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Données et réseau
3Quand les appels échouent
Intercepter les erreurs avec tryDéclencher une erreurNettoyer avec finallyL’état d’erreur de FutureBuilderUn bouton pour réessayerEntraînez-vous par vous-même : Compilateur Flutter en ligne