Menu
CoddyTech

Bắt lỗi bằng try

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

Lệnh gọi mạng có thể thất bại: điện thoại mất sóng, máy chủ ngừng hoạt động, đường dẫn không đúng. Khi fetch thất bại, nó ném ra một lỗi: ApiException, một lớp nhỏ ở đầu api.dart, có statusCode và message. Lỗi không được xử lý sẽ dừng hàm của bạn và xuất hiện dưới dạng lỗi màu đỏ trong Console, còn người dùng sẽ thấy vòng xoay tải mãi không dừng.

Bắt lỗi bằng try và catch:

try {
  final text = await fetch('/message');
  // chỉ chạy khi fetch thành công
} catch (e) {
  // chỉ chạy khi fetch ném ra ngoại lệ
  print('It failed: $e');
}

Dart chạy khối lệnh try. Nếu có bất cứ thứ gì trong khối lệnh đó ném ra lỗi, Dart chuyển thẳng đến catch, và e giữ lỗi đó. Các dòng sau dòng gây lỗi trong try sẽ không chạy.

Đặt chính await bên trong try: đó là dòng gây ra lỗi. Sau đó giải thích điều đã xảy ra bằng lời để người dùng hiểu, thay vì để ứng dụng gặp sự cố.

Để xem lỗi trong bản xem trước, viết offline = true; ở dòng đầu tiên của main rồi nhấn Chạy. offline nằm trong api.dart: nó khiến mọi lệnh gọi đều thất bại như thể điện thoại mất sóng. Xóa dòng đó trước khi nhấn Kiểm tra.

challenge icon

Thử thách

Trung bình

Hãy để loadMessage xử lý được khi lệnh gọi thất bại:

  • đặt fetch và setState sau đó vào khối try
  • trong catch (e), dừng vòng xoay và đặt thông báo thành Could not load: $e

Tự làm thử

import 'package:flutter/material.dart';

import 'api.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: MessageScreen(),
    );
  }
}

class MessageScreen extends StatefulWidget {
  const MessageScreen({super.key});

  @override
  State<MessageScreen> createState() => _MessageScreenState();
}

class _MessageScreenState extends State<MessageScreen> {
  String message = 'No message yet';
  bool loading = false;

  Future<void> loadMessage() async {
    setState(() {
      loading = true;
    });
    final text = await fetch('/message');
    setState(() {
      message = text;
      loading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            loading
                ? const CircularProgressIndicator()
                : Text(message, style: const TextStyle(fontSize: 24)),
            const SizedBox(height: 24),
            ElevatedButton(onPressed: loadMessage, child: const Text('Load message')),
          ],
        ),
      ),
    );
  }
}
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