Menu
CoddyTech

Dọn dẹp với finally

Thuộc phần Dữ liệu và mạng trong hành trình Flutter của Coddy. Bài học 12 trên 27.

Một số việc cần thực hiện dù lệnh gọi thành công hay thất bại: ẩn vòng xoay tải, bật lại nút. Nếu viết việc đó trong cả try và catch, bạn rất dễ quên một chỗ. Dart có khối thứ ba dành cho việc này, finally:

try {
  await saveName(name);
} catch (e) {
  // hiển thị lỗi
} finally {
  // luôn chạy: sau try hoặc sau catch
}

finally chạy cuối cùng, mọi lúc: sau try khi lệnh gọi thành công, sau catch khi lệnh gọi thất bại. Nhờ vậy, đây là nơi duy nhất để hoàn tác những gì bạn đã thiết lập trước lệnh gọi.

Ở đây, ứng dụng làm mờ nút Lưu trong khi lưu, bằng onPressed: saving ? null : save. Không thể nhấn nút có onPressed là null. Nếu saving không bao giờ trở lại false, nút sẽ luôn bị làm mờ.

challenge icon

Thử thách

Trung bình

Nhấn Lưu khi trường nhập trống: lỗi sẽ hiện ra, còn nút Lưu vẫn bị làm mờ, nên bạn không thể thử lại. Chuyển saving = false ra khỏi khối try và đặt vào khối finally, bên trong một setState riêng.

Tự làm thử

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 iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Dữ liệu và mạng

Tự luyện tập: Trình biên dịch Flutter online