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ờ.
Thử thách
Trung bìnhNhấ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)),
],
),
),
);
}
}
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
3Khi lời gọi hàm thất bại
Bắt lỗi bằng tryNém lỗiDọn dẹp với finallyTrạng thái lỗi của FutureBuilderNút thử lạiTự luyện tập: Trình biên dịch Flutter online