Menu
CoddyTech

Выбрасывание ошибки

Часть раздела Данные и сеть путешествия по Flutter на Coddy. Урок 11 из 27.

Ошибки бывают не только на серверах. Ваши собственные функции тоже могут отказаться продолжать работу. Если функция получает то, с чем не может работать, она выбрасывает исключение:

Future<void> saveName(String name) async {
  if (name.isEmpty) {
    throw Exception('The name cannot be empty');
  }
  // сохранить имя
}

throw останавливает функцию прямо здесь, как и return, но возвращает ошибку вместо значения. Exception('...') — это ошибка с сообщением о том, что пошло не так.

Тот, кто вызвал функцию, перехватывает ошибку с помощью try и catch, точно так же, как ошибку от fetch. При преобразовании в текст Exception начинается с Exception: , а затем идет ваше сообщение.

Настоящий fetch работает так же. Каждый ответ сервера содержит код состояния: 200 означает «ОК», 404 — «не найдено». Если код состояния не равен 200, ваш код выбрасывает исключение, поэтому на экране ошибочный ответ не отображается как данные:

final response = await http.get(Uri.parse(url));
if (response.statusCode != 200) {
  throw Exception('The server answered ${response.statusCode}');
}
return response.body;
challenge icon

Задание

Легко

Нажми Save, когда поле пустое: появляется сообщение Saved: без имени. Сделай так, чтобы saveName отклоняла пустое имя: после ожидания, если name пустое, выбрасывай Exception('The name cannot be empty'). Функция save уже перехватывает это исключение и показывает сообщение.

Попробуйте сами

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 = '';

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  Future<void> saveName(String name) async {
    await Future.delayed(const Duration(seconds: 1));
  }

  Future<void> save() async {
    try {
      await saveName(controller.text);
      setState(() {
        status = 'Saved: ${controller.text}';
      });
    } 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: save, child: const Text('Save')),
            const SizedBox(height: 16),
            Text(status, style: const TextStyle(fontSize: 18)),
          ],
        ),
      ),
    );
  }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Данные и сеть

Потренируйтесь самостоятельно: Онлайн-компилятор Flutter