Salvando informações do formulário no Android

Estamos em um formulário de uma app Android e já preenchemos praticamente todas as informações, porém assim que viramos a tela do dispositivo acabamos perdendo tudo.
Por que isso acontece? Vejamos o ciclo de vida da Activity:

Ao iniciarmos a aplicação é chamado o método onCreate(), responsável por construir toda a aplicação. Depois desse método, é chamado outro, o onStart(), que de fato inicia a aplicação. Depois de iniciada, o Android chama o onResume() que vai interagindo com o usuário, atualizando a aplicação na medida que é necessário.

Quando viramos a tela é chamado o onPause() que pausa a aplicação e em seguida o onStop() que pára tudo. Depois nossa activity é destruída através do método onDestroy() e em seguida é criada novamente, chamando o onCreate().

Então podemos concluir que nosso formulário ao ser virado, perde todas informações pelo fato dele ser destruído. Mas como podemos resolver isso? Será que da pra salvar as informações contidas nele antes de virarmos?

Poderíamos simplesmente colocar no momento que ela é pausada, mas ainda não o seria adequado, pois a qualquer instante a aplicação poderia ser matada e assim nada seria salvo. Temos um método que poderá nos ajudar neste momento que é o onSaveInstanceState(), pois ele é chamado antes da Activity ser parada. O que faz dele ser tão poderoso?

O onSaveInstanceState recebe como parâmetro um Bundle. E como este Bundle pode nos ajudar? Podemos passar para dentro dele todas as informações que queremos salvar, e é exatamente isso que estávamos buscando! Mas como fazer isso?

@Override
protected void onSaveInstanceState(Bundle outState) {
   super.onSaveInstanceState(outState);
   outState.putSerializable("nome", nome );
   outState.putSerializable("telefone", telefone );
   Log.i("Salvando", nome);
   Log.i("Salvando", telefone);


}	

Nesse caso nosso Bundle outState está usando o putSerializable() que funciona como um Map, passamos nossa chave e em seguida o valor. O bacana disto é que para nosso formulário teríamos vários putSerializable, para cada campo uma chave e valor.

Testando a nossa app, vamos girar a tela para ver o que ocorre. Usaremos o Log para verificar o que ele está salvando, no LogCat vemos o seguinte:


02-03 12:49:30.338 2930-2930/br.com.caelum.app I/Salvando: Matheus 
02-03 12:49:30.338 2930-2930/br.com.caelum.app I/Salvando: 12345678 


Estamos com todos nossos campos salvos agora, se rodarmos nossa app nesse instante e girarmos a tela veremos que nada aconteceu, ou seja, ainda estamos perdendo as informações! Por quê?

Como apenas salvamos os campos, em momento algum os restauramos. Há um jeito de pegarmos essas informações ?

Existe um outro método que é chamado assim que iniciamos o ciclo, que é o onRestoreInstanceState(). Certo, como esse método funciona?

É recebido como parâmetro um Bundle e da mesma forma que salvamos algo nele conseguimos retirar. Podemos pensar da seguinte forma: O Bundle é uma lavanderia, nossos campos são as roupas. Ao deixamos nossas roupas na lavanderia, deixamos algo que possa nos identificar quando formos retirá-las, por exemplo um telefone, cpf ou rg.

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
   super.onRestoreInstanceState(savedInstanceState);
    nome = savedInstanceState.getSerializable("nome");
    telefone = savedInstanceState.getSerializable("telefone");
    Log.i("Restaurando",  nome);
    Log.i("Restaurando", telefone);

}

Aqui estamos usando essa ideia da lavanderia: assim como nós deixamos nossas informações na lavanderia no método onSavedInstanceState(), aqui estamos pegando o savedInstanceState, que é o nosso Bundle, e pedimos nossas informações de volta, passando para cada uma delas nossa identificação. Isto acontece quando usamos o método getSerializable(), que recebe nosso identificador.

Se rodarmos novamente nossa app, preenchermos o formulário e tentarmos rodar a tela, nenhum dado se perde:


02-03 12:49:30.338 2930-2930/br.com.caelum.app I/Restaurando: Matheus 
02-03 12:49:30.338 2930-2930/br.com.caelum.app I/Restaurando: 12345678 

Excelente! Agora podemos deixar nosso usuario rodar a tela infinitas vezes e não precisamos mais nos preocupar em perder os dados que ele já havia inserido!

Vimos então que quando nossa activity muda a orientação ela é destruída. Quando estamos tratando de formulários, temos dados que nosso usuario não gostaria de perder e vimos que para solucionar esse problema existem dois métodos: onSaveInstanceState e o onRestoreInstanceStace, que nos auxiliam a persistir o dados antes de nossa activity ser destruida e resgatarmos quando for reconstruida, respectivamente.

Quer saber mais sobre Android e mobile? Aqui no Alura, dê uma olhada nos nossos cursos mobile, que tem cursos que abordam esses e muitos outros assuntos para que você construa sua primeira app completa! Também, na Caelum, temos 2 cursos presenciais do básico ao avançando!

Fique por dentro

(Última atualização em: 2 de março de 2016)

  • Sérgio Lopes

    Cê tá zuando que, tipo, 2016, e não posso virar o aparelho sem perder os dados da tela! Não sabia dessa bizarrice do Android (e do hack que você mostrou). Realmente é importante se precaver. Mas zuado isso ficar na mão do dev hein.

    Sabe se é assim no iOS tbm por exemplo? Ou só Android que é zuado?

    (na Web sei que não é; posso virar, chacoalhar, redimensionar etc e o estado continua lá)

    • Felipe Torres

      No iOS isso não acontece. As alterações numa view são mantidas mesmo após virar o aparelho.

    • Matheus Brandino

      Aqui no Android, algumas coisas ele consegue recuperar sozinho, devido ao comportamento que já foi definido na classe Activity. Entretanto fotos, listas e demais objetos ele não consegue manter sozinho.

  • Pingback: Blog do Alura – Salvando o Estado utilizando o Icepick()

Próximo ArtigoJSON e Objeto JavaScript são a mesma coisa?