Olá! Gostaríamos de dar as boas-vindas a mais um curso de Flutter aqui na Alura. Meu nome é William Bezerra e serei o instrutor ao longo de toda essa jornada.
Audiodescrição: William é um homem pardo, usa óculos e tem barba preta.
Ao longo deste curso, nós iremos construir juntos o aplicativo RunCycles. Na verdade, não construiremos o aplicativo inteiro, mas adicionaremos algumas funcionalidades relacionadas à persistência de dados. Utilizaremos o banco de dados do dispositivo do usuário para salvar informações que impactam diretamente na experiência dele ao utilizar o aplicativo.
Inicialmente, salvaremos o login do usuário. Ou seja, uma vez que o usuário entra na aplicação, precisamos armazenar, por exemplo, que ele está logado. Assim, quando ele acessar novamente, não precisará informar essas informações, pois já teremos esses dados salvos e o redirecionaremos para a tela inicial (home).
Na aplicação, o usuário conseguirá entrar e ser redirecionado para a tela inicial. Ao reiniciarmos o aplicativo, haverá uma tela de splash, que é uma tela inicial responsável por verificar se o usuário está logado ou não, redirecionando-o para a tela inicial ou para a tela de login, tudo isso com segurança.
Vamos utilizar o Flutter Secure Storage para garantir que esses dados, mesmo que salvos nos dispositivos dos usuários, só possam ser acessados utilizando a nossa aplicação. Isso é garantido por uma espécie de criptografia muito bem estruturada pelo próprio dispositivo, assegurando que esses dados estejam salvos de forma segura.
Além disso, utilizaremos o Shared Preference para salvar as preferências dos usuários. Por exemplo, podemos salvar se o tema do aplicativo será claro ou escuro. Assim, ao trocar o tema para claro e reiniciar o aplicativo, ao fechá-lo e abri-lo novamente, o tema permanecerá claro, mantendo as preferências do usuário.
Ao longo de toda a aplicação, trabalharemos com persistência de dados, o que é essencial para o desenvolvimento de aplicativos. Isso é importante tanto para quem está construindo aplicativos quanto para quem já atua no mercado, pois permite implementar funcionalidades específicas e salvar preferências dos usuários. Utilizaremos a estrutura do dispositivo do usuário, aproveitando o espaço de armazenamento para salvar esses dados.
Se você gostou, compartilhe este curso com seus amigos para estudarem juntos. Nos vemos na próxima aula.
Para iniciarmos, vamos considerar o seguinte cenário: fomos contratados pela RunCycles para dar continuidade ao aplicativo deles. Nossa tarefa é desenvolver duas funcionalidades específicas dentro da aplicação, pois existem dois problemas ocorrendo atualmente.
O primeiro problema está relacionado à persistência do login. Ao entrar no aplicativo RunCycles, conseguimos fazer o login inserindo e-mail e senha. No entanto, esse login não é persistido, ou seja, ao reiniciar a aplicação, o usuário precisa logar novamente. Isso prejudica a experiência do usuário. Imagine se, toda vez que acessássemos o Instagram, tivéssemos que inserir nossos dados novamente. Seria uma experiência muito ruim.
Além desse problema, há outro relacionado à persistência de tema. Podemos alternar entre o tema claro e o tema escuro, e a aplicação responde adequadamente a essa mudança. No entanto, ao reiniciar o aplicativo, ele não mantém a configuração de tema escolhida, não salvando esse dado.
Precisamos atuar nesses dois fluxos, salvando esses dados no banco de dados local do aplicativo do usuário, ou seja, precisamos armazenar essas informações na memória.
Como fazemos isso com o Flutter? Existem diversas maneiras de abordar essa questão, desde as mais simples até as mais complexas. Podemos criar banco de dados, fazer integração e toda uma estrutura. No entanto, para o nosso contexto, como estamos lidando com apenas dois dados, vamos começar pela abordagem mais simples possível. Essa abordagem se refere tanto à parte de salvar uma chave e um dado quanto a salvar algo com mais segurança.
Vamos iniciar pelo que é mais simples dentro desse contexto, que é a função de salvar dados com chave e valor, semelhante a um JSON. Para isso, utilizaremos um package chamado SharedPreferences
, que utiliza a estrutura nativa de banco de dados tanto do Android quanto do iOS para salvar esses dados. É isso que começaremos a implementar.
Dentro do VSCode, abriremos o terminal e executaremos o comando para adicionar o pacote necessário ao nosso projeto. Primeiro, vamos adicionar o comando base:
flutter pub add
Em seguida, adicionamos o pacote específico que precisamos:
flutter pub add shared_preferences
Com isso, ele adicionará ao nosso pubspec.yaml
essa dependência necessária, que orquestrará o salvamento dos dados, independentemente da plataforma. É como se fosse uma abstração que, no Android, utiliza o próprio SharedPreferences
, que é o nome da tecnologia do Android para salvar dados, e no iOS utiliza o NSUserDefaults
. Assim, ele trabalha essa estrutura para usar os esquemas nativos específicos para salvar esses dados.
Após adicionar o package à aplicação, o arquivo pubspec.yaml
será atualizado para incluir a versão do pacote:
shared_preferences: ^2.5.3
Agora que configuramos o pacote SharedPreferences
, podemos prosseguir para a implementação das funcionalidades de persistência de login e tema.
Para entendermos o funcionamento do SharedPreference, vamos utilizar a tela inicial do nosso aplicativo, a LoginScreen
, e realizar alguns testes para compreender todo esse funcionamento. Basicamente, vamos criar uma instância, por exemplo, finalSharedPreference
, que será igual ao SharedPreference
. Selecionaremos a opção que já traz o import necessário. Em seguida, faremos um SharedPreference.getInstance
, que criará uma instância, um pattern (padrão), para utilizar o Preference, armazenando-a em uma variável.
Vamos começar criando a instância do SharedPreferences
:
final sharedPreferences = SharedPreferences.getInstance();
Com essa configuração do SharedPreference, podemos realizar interações. Basicamente, são de três a quatro operações que podemos executar, dependendo de como imaginamos. As operações são: adição (para adicionar um novo dado), exclusão (para excluir um dado), edição (para editar um dado) e get (para obter um dado). Essas são as quatro estruturas que normalmente utilizamos no estilo de CRUD.
Vamos validar como isso seria feito. Começaremos pela criação, com a função voidCreate
. Vamos criar algumas funções para testar, ainda que não seja a aplicação da melhor maneira possível, apenas para entender como funciona o SharedPreference. A criação é simples: chamamos a própria instância que temos. Nesse caso, é uma instância futura, então precisamos esperar que aconteça. Teremos, em teoria, um finalPreference
igual ao ageSharedPreference
. Com isso, conseguimos usar o Preference e até verificar alguns métodos como get
e clear
. Utilizaremos o método set
, que é usado para criar.
Vamos implementar a função create
para adicionar um dado booleano:
void create({required bool isThemeLight}) async {
final preferences = await sharedPreferences;
await preferences.setBool('isThemeLight', isThemeLight);
}
O SharedPreference possui cinco tipos para adicionar dados: bool, double, int, string e lista de string. Não mais do que isso. Se quisermos salvar informações mais estruturadas, como um JSON, o SharedPreference não é tão indicado. Existem formas de utilizá-lo nesse contexto, mas ele não é recomendado para aplicações com muitos dados. Para coisas pequenas, sim. Por exemplo, queremos salvar uma informação ou outra, pois ele é mais interessante nesse contexto.
Para obter o dado, o processo é semelhante, mas utilizamos o get. Por exemplo, getInfo
ou getTem
, que é mais fácil. Também instanciamos o sharedPreference
, transformamos a função em assíncrona e utilizamos preference.get
. Definimos se é bool, double ou int; neste caso, bool. Passamos o nome da chave que queremos obter, como getBoolTemLight
, e ele nos retorna o valor. O getBool
não é um future, pois, ao instanciar, ele já traz tudo que está salvo. O ideal é definir um tipo e retornar esse tipo. O retorno será nullable, pois pode não existir um dado salvo. Na maioria das vezes, o primeiro dado não existirá na aplicação.
Vamos implementar a função getTheme
para obter o valor salvo:
Future<bool?> getTheme() async {
final preferences = await sharedPreferences;
return preferences.getBool('isThemeLight');
}
Além disso, como é future, precisamos adicionar o future ao tipo da função. Assim, já temos os dois métodos: um para criar e outro para obter.
Nesse caso, mencionamos que poderiam ser três ou quatro funções, dependendo do contexto. Na verdade, o terceiro seria o editar, mas o editar é basicamente um criar com o mesmo nome. Ou seja, se já definimos inicialmente o stemLight
como True
e mudamos para False
, chamamos esse mesmo método com a mesma variável, salvando por cima. Assim, ele apenas troca o valor dentro da variável. Esse seria o editar.
Por fim, temos o excluir, que é bem simples nessa estrutura. Vamos ter um método void delete
, instanciar o preference
, que sempre será instanciado, e transformá-lo em async (assíncrono). Basta chamar o preference
. Temos o get
, o clear
, que limpa tudo, e o remove
, onde passamos o nome da variável que queremos remover. Nesse caso, queremos remover o stemLight
, e ele será removido. É future (futuro) também, então precisamos adicionar um await
. Com isso, está removido.
Vamos implementar a função delete
para remover o dado:
void delete() async {
final preferences = await sharedPreferences;
await preferences.remove('isThemeLight');
}
Se quisermos apagar todos os dados salvos na aplicação, chamamos o preference.clear
, que limpa tudo e zera novamente. Mas não é o caso aqui, pois só queremos apagar um dado específico. Basicamente, são essas três estruturas. Lembrando que o create
pode ser usado tanto para criar novos dados quanto para editar um dado já existente.
Para finalizar, vamos implementar essas funções e testá-las para ver se realmente estão funcionando. Vamos criar dois botões dentro da column
, na verdade três, um para cada função, para testar o retorno de cada um. Vamos criar um IconButton
que vai salvar. Primeiro, chamaremos o IconButton
de salvar, que chamará a função create
, recebendo se o tema é light (claro) ou não. Nesse caso, passaremos sempre como true
, já que não estamos trabalhando com nenhuma interação ou coisa do tipo. Vamos adicionar um ícone aqui, Icons.save
. Perfeito, há um disponível.
Vamos criar os botões para interagir com as funções:
IconButton(
onPressed: () async {
await create(isThemeLight: true);
},
icon: Icon(Icons.save),
),
IconButton(
onPressed: () async {
final result = await getTheme();
print('RESULT: $result');
},
icon: Icon(Icons.search),
),
IconButton(
onPressed: () {
delete();
},
icon: Icon(Icons.remove),
),
Pronto, dentro da nossa home, já temos os três botões: salvar, buscar e apagar. Vamos abrir o debug console. A estrutura funciona da seguinte maneira: se tentarmos buscar agora, ele retornará "non-implementation folder". Isso ocorre porque, após instalar o pacote, ainda não reinstalamos o aplicativo. Um ponto importante é que, se adicionarmos o pacote, devemos parar a aplicação e rodá-la novamente, pois ele precisa baixar os dados nativos para a implementação. Vamos rodar e já voltamos.
Pronto, a aplicação executou novamente. Se voltarmos ao VS Code, vamos limpar o console e fechar os arquivos, deixando tudo organizado para acompanhar. Ao clicar em buscar, ele trouxe o resultado como nulo. Isso ocorre porque ainda não temos nada salvo. Agora, ao clicar em salvar, ele executou. Se voltarmos e clicarmos em buscar novamente, ele retornará o resultado como true
, pois agora está salvo.
Se reiniciarmos a aplicação, que é o motivo de toda essa configuração, ao clicar em buscar sem adicionar antes, ao invés de retornar como nulo, ele deveria retornar o resultado, que nesse caso seria true
. Vamos verificar. Clicando em buscar, ele retornará um resultado true
, indicando que o dado salvo anteriormente ainda está dentro da aplicação. Se clicarmos para deletar, o dado será apagado. Agora, ao buscar, ele deve retornar como nulo. Da mesma forma, se reiniciarmos a aplicação, ao buscar esse dado, ele também estará nulo.
Ou seja, já temos uma estrutura pronta para trabalhar com a questão de salvar dados dentro da aplicação. É exatamente isso que faremos agora: pegar toda essa estrutura que aprendemos e aplicá-la no contexto do aplicativo, inicialmente para salvar o dado da troca de tema.
O curso Flutter: Persistência de Dados com SharedPreferences e Secure Storage possui 72 minutos de vídeos, em um total de 24 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:
Mobile, Programação, Front-end, DevOps, UX & Design, Marketing Digital, Data Science, Inovação & Gestão, Inteligência Artificial
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ê participa de eventos exclusivos, pode tirar dúvidas em estudos colaborativos e ainda conta com mentorias em grupo com especialistas de diversas á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.
Para estudantes ultra comprometidos atingirem seu objetivo mais rápido.
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.
Conecte-se ao mercado com mentoria personalizada, vagas exclusivas e networking estratégico que impulsionam sua carreira tech para o próximo nível.