Menu
CoddyTech

Fazendo a limpeza com finally

Parte da seção Dados e rede do Journey de Flutter da Coddy. Lição 12 de 27.

Algumas tarefas precisam acontecer independentemente de uma chamada ter funcionado ou falhado: ocultar o indicador de carregamento, reativar um botão. É fácil esquecer de escrever isso em um dos blocos, try ou catch. Dart tem um terceiro bloco para isso, finally:

try {
  await saveName(name);
} catch (e) {
  // mostra o erro
} finally {
  // sempre é executado: depois de try ou de catch
}

finally é executado por último, sempre: depois de try, quando a chamada funciona, e depois de catch, quando ela falha. Assim, esse é o lugar certo para desfazer o que você preparou antes da chamada.

Aqui, o app desativa o botão Salvar enquanto salva, usando onPressed: saving ? null : save. Não é possível pressionar um botão cujo onPressed seja null. Se saving nunca voltar a false, o botão ficará desativado para sempre.

challenge icon

Desafio

Médio

Salve com o campo vazio: o erro é exibido, e Salvar permanece cinza, então você nunca pode tentar novamente. Mova saving = false para fora do bloco try, para um bloco finally, em seu próprio setState.

Experimente você mesmo

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 iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Dados e rede

Pratique por conta própria: Compilador de Flutter online