Menu
CoddyTech

Limpiar con finally

Parte de la sección Datos y red del Journey de Flutter de Coddy. Lección 12 de 27.

Hay tareas que deben realizarse tanto si una llamada funciona como si falla: ocultar el indicador de carga, volver a habilitar un botón. Es fácil olvidarse de escribirlo en uno de los bloques, try o catch. Dart tiene un tercer bloque para ello, finally:

try {
  await saveName(name);
} catch (e) {
  // muestra el error
} finally {
  // siempre se ejecuta: después de try o después de catch
}

finally se ejecuta al final, siempre: después de try cuando funciona, después de catch cuando falla. Eso lo convierte en el lugar adecuado para deshacer lo que preparaste antes de la llamada.

Aquí, la aplicación deshabilita Save mientras guarda, con onPressed: saving ? null : save. No se puede pulsar un botón cuyo onPressed es null. Si saving nunca vuelve a ser false, el botón se queda deshabilitado para siempre.

challenge icon

Desafío

Intermedio

Guarda con el campo vacío: aparece el error y Guardar sigue en gris, así que no puedes volver a intentarlo. Mueve saving = false fuera del bloque try y dentro de un bloque finally, en su propio setState.

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 = '';
  bool saving = false;

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

  Future<void> saveName(String name) async {
    await Future.delayed(const Duration(seconds: 1));
    if (name.isEmpty) {
      throw Exception('The name cannot be empty');
    }
  }

  Future<void> save() async {
    setState(() {
      saving = true;
    });
    try {
      await saveName(controller.text);
      setState(() {
        status = 'Saved: ${controller.text}';
        saving = false;
      });
    } 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: saving ? null : 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