Menu
CoddyTech

Aufräumen mit finally

Teil des Abschnitts Daten und Netzwerk der Flutter-Journey von Coddy. Lektion 12 von 27.

Manche Arbeiten müssen erledigt werden, unabhängig davon, ob ein Aufruf erfolgreich war oder fehlgeschlagen ist: den Ladeindikator ausblenden, eine Schaltfläche wieder aktivieren. Schreibt man den Code sowohl in try als auch in catch, vergisst man ihn leicht an einer der beiden Stellen. Dart hat dafür einen dritten Block: finally:

try {
  await saveName(name);
} catch (e) {
  // zeige den Fehler an
} finally {
  // wird immer ausgeführt: nach try oder nach catch
}

finally wird immer zuletzt ausgeführt: nach try, wenn der Aufruf erfolgreich war, und nach catch, wenn er fehlgeschlagen ist. So ist es der eine Ort, an dem du rückgängig machen kannst, was du vor dem Aufruf eingerichtet hast.

Hier blendet die App die Schaltfläche Speichern während des Speicherns aus, mit onPressed: saving ? null : save. Eine Schaltfläche, deren onPressed den Wert null hat, kann nicht gedrückt werden. Wenn saving nicht wieder auf false gesetzt wird, bleibt die Schaltfläche dauerhaft grau.

challenge icon

Aufgabe

Mittel

Speichere mit einem leeren Feld: Der Fehler wird angezeigt, und Save bleibt grau, sodass du es nie erneut versuchen kannst. Verschiebe saving = false aus dem try-Block in einen finally-Block, in ein eigenes setState.

Probier es selbst

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 iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Daten und Netzwerk

Übe selbstständig: Online-Flutter-Compiler