Olá, meu nome é Ricarth Lima, e serei seu instrutor em mais um curso de Dart!
Audiodescrição: Ricarth é um homem com cabelo black power, utiliza óculos de armação quadrada transparente, possui pele dourada, barba e bigode. Está de camiseta preta, e o fundo, de parede branca, está iluminada por luzes em tons de roxo e azul, e há prateleiras com livros diversos e alguns bonecos.
Boas-vindas ao curso de Dart: lidando com erros, exceções e null safety. Este assunto é muito importante, estou muito empolgado. O projeto do curso será uma continuação direta do curso anterior, um chatbot do Banco d'Ouro, porém, com um detalhe: no curso anterior não preparamos o programa para eventuais erros, uma situação excepcional como uma queda de internet ou a não resposta do servidor, entre outras.
Não preparamos uma mensagem amigável que traga a clareza desejada, sem o qual nosso programa quebraria:
Não foi possível alcançar o servidor.
Tente novamente mais tarde.
Failed host lookup: 'api.github.com.br'
https://api.github.com.br/gists/413c0aefe6c6abc464581c29029c8ace
2024-08-07 16:24:14.004242 | ocorreu uma tentativa de consulta.
Como eu posso te ajudar? (digite o número desejado)
1 - Ver todas suas contas.
2 - Adicionar nova conta.
3 - Sair
Esse pensamento de que nem sempre o caminho feliz vai ocorrer, e que precisamos preparar o programa para que ele lide com caminhos excepcionais é muito importante. É essencial termos essa noção para entrada no mercado de trabalho usando Dart e Flutter, pois a aplicação não pode quebrar, travar, ficar carregando infinitamente na tela da pessoa usuária.
Atenção! Como pré-requisito, é importante ter realizado o curso anterior de Dart com aassincronismo e APIs, justamente porque trabalharemos no mesmo projeto, e os conhecimentos aprendidos neste curso serão úteis.
Estou muito animado para começar, vamos por a mão na massa?
Estamos desenvolvendo uma aplicação que gerencia um chatbot para as contas do nosso Banco d'Ouro, que começamos no curso anterior. No entanto, há um grande detalhe a ser considerado. Vamos abrir o terminal com "Ctrl + J", ajustar sua posição para melhorar a visualização e executar usando dart run bin/main.dart
. Vamos ver como isso se comporta.
Perfeito! O chatbot, Lewis, aparece corretamente. Se pressionarmos "Enter", ele exibe o resultado. O número 2 adiciona uma nova opção, e com o número 3, saímos. Você notou algum problema aqui? Exatamente, nenhum! Essa resposta pode parecer estranha, mas é porque estamos apenas considerando o cenário ideal do nosso projeto.
Quando começamos a programar, temos a tendência, como pessoas desenvolvedoras, de pensar apenas nesse cenário ideal. Ou seja, se nada der errado, qual será o caminho que a pessoa usuária seguirá? No entanto, esse "se nada der errado" é muito otimista. Na vida real, quando lidamos com aplicações conectadas à Web ou com aplicações em dispositivos com baixa capacidade de hardware, como os dispositivos móveis em comparação aos computadores, por exemplo, erros podem surgir e fugir do nosso controle. Nosso programa precisa estar preparado para lidar com essas situações.
Nessa aplicação, que ainda é bastante simples, o que poderia dar errado de imediato? Talvez a internet da pessoa usuária caia. Será que o programa vai travar? Não deveria. E se tivéssemos passado um servidor incorreto? Se, ao tentarmos nos comunicar com nosso servidor, nossa API, por algum motivo ou ação da pessoa usuária, acabamos indo parar num servidor incorreto. O que acontecerá?
Para não ter que desconectar o cabo de internet e provar que algo acontece quando a internet cai, vamos alterar intencionalmente nosso servidor. Então, se formos até a estrutura do projeto usando o atalho "Ctrl + B", teremos a pasta services
. Dentro da pasta de serviços, temos account_service.dart
. Na linha 12 deste arquivo, veremos que chamamos a API do github.com
no subdiretório gists
com o ID do nosso gist
. E se em vez de ".com", digitássemos ".br" por engano? Vamos salvar e rodar para ver o que acontece.
Após salvarmos, vamos abrir o terminal com "Ctrl + J", limpá-lo usando o comando clear
e rodar dart run bin/main.dart
. O chatbot rodou, vamos tentar visualizar uma conta digitando a opção "1" no terminal, o que fará a primeira requisição com o servidor. Aconteceu um erro inesperado.
Enfatizaremos muito neste curso que os erros, as exceções, os problemas que o Dart nos dá não são inimigos. Pelo contrário. Sabemos que quando começamos a programar, é comum sentir um pouco de desespero nestes momentos. O coração bate mais rápido, você começa a pensar que fez algo errado, não sabe o que fazer, até porque muitas vezes esses erros vêm em inglês, e por aí vai.
Precisamos inicialmente nos acalmar e ler detalhadamente o que nos foi dito. Na primeira linha, vemos que uma exceção não foi tratada. Ou seja, chegamos a um caso excepcional, em um caminho que não é o ideal e não lidamos com isso, o que leva o programa a quebrar.
A seguir, temos que houve uma ClientException
com SocketException
. São dois problemas que existem dentro do pacote HTTP, além de informações adicionais. Falhamos em nos comunicar com esse host, api.github.com.br
. O host não é conhecido, já que nós forçamos essa situação, mas isso poderia ter acontecido de outra maneira. Poderíamos checar no código e verificar que de fato colocamos .br
em vez de .com.br
.
Seguindo na leitura das mensagens de erro, as linhas que mostram #0
, #1
, #2
, indicam o caminho que a exceção não tratada tomou. Então, o primeiro método que causou o erro não estava sob nosso controle, porque ele estava no pacote HTTP, o método send
do IOClient
. Depois, vemos o BaseClient._sendUnstreamed
, que também não controlamos, assim como o _withClient
. Se prestarmos atenção em cada uma dessas linhas, tanto a #0
, quanto a #1
e a #2
, são do pacote (package
) HTTP.
Na linha 3, o AccountService.getAll
indica uma classe chamada AccountService
que tem um método getAll
. O pacote é indicado: o dart_exceptions
, o services
, na pasta serviço, com o account_service.dart
. Além disso, são indicados a linha e a posição do caractere onde o erro se deu: linha 16 na posição 25. Para confirmar, podemos usar o "Ctrl + J" para encontrar a linha 16, e imaginar que muito provavelmente o erro se dá no get
.
Voltando às mensagens de erro no terminal, também temos que o getAll
não soube lidar com isso, "enviando" o problema para o _getAllAccounts
, que fica na nossa tela, a qual também não soube lidar, mandando a exceção para "mais longe" ainda, o runChatBot
que fica na main
, que por fim não soube lidar, e isso matou a aplicação, pois não foi mais possível rodá-la.
Nota-se que não é para ter medo deste tipo de situação. É importante reforçar que todos os erros que surgirem, principalmente em pacotes bem escritos como o HTTP, vão nos dando pistas para conseguirmos corrigi-los da melhor forma possível.
Diferentemente deste exemplo, em que forçamos uma exceção, a seguir aprenderemos a lidar com elas de fato!
Entendemos que erros podem ocorrer e que o que aparece na tela não é nosso inimigo, pelo contrário, nos ajudam a entender o que está acontecendo no código. No entanto, a pessoa usuária da nossa aplicação não tem acesso a todo esse código em inglês, que tampouco vai significar algo para ela, certo? Para ajudá-la, precisamos tratar essa exceção.
Nosso terminal indica que houve uma exceção que não foi tratada, e ela representa justamente um caminho que não é ideal, ou seja, aquele que projetamos para ser perfeito. Quando falamos de exceção no Dart, estamos nos referindo a um objeto. Tudo é um objeto, portanto a exceção não é diferente. Trata-se de um objeto a ser lançado por quem o notou. Neste caso, quando o problema ocorre, o HTTP lança o que chamamos de exceção. Mas, se não o capturarmos em algum lugar, o problema vai sendo "escalado" para trechos de código mais externos, que vão repassando-o, até a aplicação travar.
Para evitar isso, vamos identificar onde o getAll
da linha 3 está sendo chamado. Temos que é na AccountScreen
, no _getAllAccounts
. Vamos para lá usando "Ctrl + J" e "Ctrl + B" para abrir o explorador. Na pasta "screens", abriremos account_screen.dart
, e usaremos o "Ctrl + B" de novo, para fecharmos o explorador. Na parte de baixo do código, há o _getAllAccounts()
, e na linha de baixo, a 59, o getAll()
está sendo chamado, e ela pode lançar uma exceção.
Para tratarmos a exceção, cercaremos esta linha e tudo que depende dela com o famoso bloco Try, que significa "tentar" em inglês. Ou seja, estamos indicando ao Dart: "Tente executar esse bloco de código com pelo menos uma linha que pode causar uma exceção". Na linha 58, vamos quebrar uma linha, escrever Try
, e tirar a chave do final, colocando-a na linha 62:
_getAllAcounts() async {
try{
List<Account> listAccounts = await _accountService.getAll();
print(listAccounts);
}
}
Porém, o bloco try
não é o suficiente, pois se alguma exceção acontecer, o Dart precisa saber o que fazer. Um bloco try
precisa ser seguido por um on
, um catch
ou um finally
: um on
pode significar que uma exceção foi identificada, um catch
significa pegar essa exceção identificada, e um finally
basicamente informa ao programa que o bloco deverá ser rodado, não importa se uma exceção foi identificada ou não. Por enquanto, vamos começar com um on Exception
:
_getAllAcounts() async {
try{
List<Account> listAccounts = await _accountService.getAll();
print(listAccounts);
} on Exception {
}
}
Quando a aplicação notar uma exceção, ela vai tentar rodar o bloco das linhas 61 a 62, dentro do try
. Se houver de fato uma exceção, o bloco que começa na linha 63 será rodado. Este bloco terá algo super plausível de se ter num chatbot, por exemplo a mensagem "não consegui recuperar os dados da conta" em um print
, seguido de outro:
_getAllAcounts() async {
try{
List<Account> listAccounts = await _accountService.getAll();
print(listAccounts);
} on Exception {
print("Não consegui recuperar os dados da conta.");
print("Tente novamente mais tarde.");
}
}
Deste modo, a nova linha 60 pode ocasionar um problema. Escolhemos lidar com possíveis exceções no getAll()
. Cercamos a linha 60 e a dependente, 61, com o bloco try
. Como o próprio Dart diz, o try
não funciona sozinho, e no nosso caso, usamos o on
para indicar o que deve ser feito: comparar se essa exceção é uma Exception
. Vamos rodar e ver o que acontece com o "Ctrl + J" e dart run bin/main.dart
.
Inicialmente, parece que funcionou. O problema é quando tentamos consultar todas as contas. Digitaremos a opção "1", e temos um resultado muito melhor! Tivemos duas mudanças muito importantes: primeiro, recebemos um feedback. Notamos uma situação problemática e conseguimos tratá-la.
Segunda mudança, e a mais importante: a aplicação não travou, justamente porque a exceção não lidada não chegou na nossa main
. Ótimo, agora vamos aprofundar mais nas possibilidades do try
.
O curso Dart: lidando com erros, exceções e null safety possui 150 minutos de vídeos, em um total de 60 atividades. Gostou? Conheça nossos outros cursos de Flutter em Mobile, ou leia nossos artigos de Mobile.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.