Menu
CoddyTech

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;
challenge icon

Desafío

Fácil

Toca 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)),
          ],
        ),
      ),
    );
  }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Datos y red

Practica por tu cuenta: Compilador de Flutter online