Выбрасывание ошибки
Часть раздела Данные и сеть путешествия по 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;Задание
ЛегкоНажми 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)),
],
),
),
);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Данные и сеть
1Future (асинхронные результаты)
Значение, которое появится позжеОжидание с async и awaitФункции, возвращающие FutureПрактический API Coddy3Когда вызовы завершаются ошибкой
Перехват ошибок с помощью tryВыбрасывание ошибкиОчистка с помощью finallyСостояние ошибки в FutureBuilderКнопка «Попробовать снова»Потренируйтесь самостоятельно: Онлайн-компилятор Flutter