Throwing an Error
Part of the Data and the Network section of Coddy's Flutter journey. Lesson 11 of 27.
Errors are not only for servers. Your own functions can refuse to go on. When a function gets something it cannot work with, it throws:
Future<void> saveName(String name) async {
if (name.isEmpty) {
throw Exception('The name cannot be empty');
}
// save the name
}throw stops the function right there, like return, but it hands back an error instead of a value. Exception('...') is the error, with a message that says what went wrong.
Whoever called the function catches it with try and catch, exactly like an error from fetch. Turned into text, an Exception starts with Exception: , then your message.
This is how a real fetch works too. Every answer from a server comes with a status code: 200 means OK, 404 means not found. When it is not 200, your code throws, so the screen never shows a broken answer as if it were data:
final response = await http.get(Uri.parse(url));
if (response.statusCode != 200) {
throw Exception('The server answered ${response.statusCode}');
}
return response.body;Challenge
EasyTap Save with the field empty: it says Saved: with no name. Make saveName refuse an empty name: after the wait, if name is empty, throw Exception('The name cannot be empty'). The save function already catches it and shows the message.
Try it yourself
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)),
],
),
),
);
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Data and the Network
Practice on your own: Online Flutter compiler