Sprzątanie za pomocą finally
Część sekcji Dane i sieć ścieżki Flutter w Coddy. Lekcja 12 z 27.
Niezależnie od tego, czy wywołanie się powiedzie, czy nie, trzeba wykonać pewne czynności: ukryć wskaźnik ładowania, ponownie włączyć przycisk. Łatwo zapomnieć o zapisaniu tego zarówno w try, jak i w catch. Dart ma trzeci blok do tego celu: finally:
try {
await saveName(name);
} catch (e) {
// wyświetl błąd
} finally {
// wykonuje się zawsze: po try lub po catch
}finally wykonuje się na końcu, za każdym razem: po try, gdy wywołanie się powiedzie, albo po catch, gdy się nie powiedzie. Dzięki temu jest to jedyne miejsce, w którym można cofnąć to, co zostało przygotowane przed wywołaniem.
Tutaj aplikacja wyszarza przycisk Save na czas zapisywania, używając onPressed: saving ? null : save. Nie można nacisnąć przycisku, którego onPressed ma wartość null. Jeśli saving nigdy nie zmieni się z powrotem na false, przycisk na stałe pozostanie wyszarzony.
Wyzwanie
ŚredniZapisz przy pustym polu: pojawi się błąd, a przycisk Zapisz pozostanie wyszarzony, więc nie będzie można spróbować ponownie. Przenieś saving = false z bloku try do bloku finally, umieszczając go we własnym setState.
Spróbuj swoich sił
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)),
],
),
),
);
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Dane i sieć
3Gdy wywołania kończą się niepowodzeniem
Przechwytywanie błędów za pomocą tryZgłaszanie błęduSprzątanie za pomocą finallyStan błędu w FutureBuilderPrzycisk „Spróbuj ponownie”Poćwicz samodzielnie: Kompilator Flutter online