Lanzar un error
Parte de la sección Datos y red del Journey de Flutter de Coddy. Lección 11 de 27.
Los errores no son solo cosa de los servidores. Tus propias funciones pueden negarse a continuar. Cuando una función recibe algo con lo que no puede trabajar, lanza una excepción:
Future<void> saveName(String name) async {
if (name.isEmpty) {
throw Exception('The name cannot be empty');
}
// guarda el nombre
}throw detiene la función justo ahí, como return, pero devuelve un error en lugar de un valor. Exception('...') es el error, con un mensaje que indica qué salió mal.
Quien haya llamado a la función captura el error con try y catch, exactamente como un error de fetch. Al convertirse en texto, una Exception empieza con Exception: , seguido de tu mensaje.
Así también funciona un fetch real. Cada respuesta de un servidor viene con un código de estado: 200 significa que todo está bien, 404 significa que no se encontró. Cuando no es 200, tu código lanza una excepción, para que la pantalla nunca muestre una respuesta fallida como si fueran datos:
final response = await http.get(Uri.parse(url));
if (response.statusCode != 200) {
throw Exception('The server answered ${response.statusCode}');
}
return response.body;Desafío
FácilToca Save con el campo vacío: aparece Saved: sin ningún nombre. Haz que saveName rechace un nombre vacío: después de la espera, si name está vacío, lanza Exception('The name cannot be empty'). La función save ya captura la excepción y muestra el mensaje.
Pruébalo tú mismo
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)),
],
),
),
);
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Datos y red
3Cuando fallan las llamadas
Capturar errores con tryLanzar un errorLimpiar con finallyEl estado de error de FutureBuilderUn botón para volver a intentarloPractica por tu cuenta: Compilador de Flutter online