Estou tentando salvar e restaurar o estado de um Activity
usando os métodos onSaveInstanceState()
e onRestoreInstanceState()
.
O problema é que isso nunca entra no onRestoreInstanceState()
método. Alguém pode me explicar por que isso acontece?
Estou tentando salvar e restaurar o estado de um Activity
usando os métodos onSaveInstanceState()
e onRestoreInstanceState()
.
O problema é que isso nunca entra no onRestoreInstanceState()
método. Alguém pode me explicar por que isso acontece?
Respostas:
Normalmente, você restaura seu estado em onCreate()
. Também é possível restaurá-lo onRestoreInstanceState()
, mas não é muito comum. ( onRestoreInstanceState()
é chamado depois onStart()
, enquanto onCreate()
é chamado antes onStart()
.
Use os métodos put para armazenar valores em onSaveInstanceState()
:
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
icicle.putLong("param", value);
}
E restaure os valores em onCreate()
:
public void onCreate(Bundle icicle) {
if (icicle != null){
value = icicle.getLong("param");
}
}
onRestoreInstanceState()
é chamado apenas ao recriar a atividade depois de eliminada pelo sistema operacional. Tal situação acontece quando:
Em contraste: se você está em sua atividade e acerta Back
aperta o botão do dispositivo, sua atividade é concluída () ed (ou seja, pense nisso como sair do aplicativo de desktop) e da próxima vez que você iniciar seu aplicativo, ele será iniciado "fresco", ou seja, sem estado salvo porque você saiu dele intencionalmente ao bater Back
.
Outra fonte de confusão é que, quando um aplicativo perde o foco, outro aplicativo onSaveInstanceState()
é chamado, mas quando você navega de volta para o aplicativo, ele onRestoreInstanceState()
pode não ser chamado. Este é o caso descrito na pergunta original, ou seja, se sua atividade NÃO foi interrompida durante o período em que outra atividade estava em sua frente onRestoreInstanceState()
, NÃO será chamado porque sua atividade está praticamente "viva".
Em suma, conforme declarado na documentação para onRestoreInstanceState()
:
A maioria das implementações simplesmente usará onCreate (Bundle) para restaurar seu estado, mas às vezes é conveniente fazer isso aqui depois que toda a inicialização foi feita ou para permitir que as subclasses decidam se devem usar sua implementação padrão. A implementação padrão desse método executa uma restauração de qualquer estado de exibição que foi previamente congelado por onSaveInstanceState (Bundle).
Pelo que li: Não há razão para substituir a onRestoreInstanceState()
menos que você esteja criando uma subclasse Activity
e seja esperado que alguém crie uma subclasse de sua subclasse.
O estado em que você salva onSaveInstanceState()
está disponível posteriormente na onCreate()
invocação do método. Portanto, use onCreate
(e seu Bundle
parâmetro) para restaurar o estado de sua atividade.
Como alternativa, você pode armazenar um pacote com os dados que deseja manter no Intent usado para iniciar a atividade A.
Intent intent = new Intent(this, ActivityA.class);
intent.putExtra("bundle", theBundledData);
startActivity(intent);
A Atividade A teria que passar isso de volta para a Atividade B. Você recuperaria o intent no método onCreate da Atividade B.
Intent intent = getIntent();
Bundle intentBundle;
if (intent != null)
intentBundle = intent.getBundleExtra("bundle");
// Do something with the data.
Outra ideia é criar uma classe de repositório para armazenar o estado da atividade e fazer com que cada uma de suas atividades faça referência a essa classe (possível usando uma estrutura singleton). Porém, fazer isso provavelmente é mais problemático do que compensa.
O principal é que, se você não armazenar onSaveInstanceState()
, onRestoreInstanceState()
não será chamado. Esta é a principal diferença entre restoreInstanceState()
e onCreate()
. Certifique-se de realmente armazenar algo. Provavelmente este é o seu problema.
Descobri que onSaveInstanceState é sempre chamado quando outra Activity vem para o primeiro plano. E onStop também.
No entanto, onRestoreInstanceState foi chamado apenas quando onCreate e onStart também foram chamados. E onCreate e onStart NÃO eram sempre chamados.
Portanto, parece que o Android nem sempre exclui as informações de estado, mesmo que a atividade passe para o segundo plano. No entanto, ele chama os métodos de ciclo de vida para salvar o estado apenas por segurança. Portanto, se o estado não for excluído, o Android não chamará os métodos de ciclo de vida para restaurar o estado, pois eles não são necessários.
A Figura 2 descreve isso.
Não é necessário que onRestoreInstanceState seja sempre chamado após onSaveInstanceState.
Observe que: onRestoreInstanceState sempre será chamado, quando a atividade for girada (quando a orientação não for controlada) ou abrir sua atividade e, em seguida, abrir outros aplicativos para que sua instância de atividade seja apagada da memória pelo SO.
Na documentação Restaurar o estado da IU da atividade usando o estado da instância salva , é declarado como:
Em vez de restaurar o estado durante onCreate (), você pode escolher implementar onRestoreInstanceState (), que o sistema chama após o método onStart (). O sistema chama onRestoreInstanceState () apenas se houver um estado salvo para restaurar, portanto , você não precisa verificar se o Bundle é nulo :
IMO, esta é uma forma mais clara do que verificar na onCreate, e se encaixa melhor com o princípio de responsabilidade única.
No meu caso, onRestoreInstanceState
foi chamado quando a atividade foi reconstruída após alterar a orientação do dispositivo. onCreate(Bundle)
foi chamado primeiro, mas o pacote não tinha a chave / valores que eu defini com onSaveInstanceState(Bundle)
.
Em seguida, onRestoreInstanceState(Bundle)
foi chamado com um pacote que continha as chaves / valores corretos.
Acabei de me deparar com isso e percebi que a documentação tinha minha resposta:
"Esta função nunca será chamada com um estado nulo."
No meu caso, estava me perguntando por que onRestoreInstanceState não estava sendo chamado na instanciação inicial. Isso também significa que, se você não armazenar nada, ele não será chamado quando você reconstruir sua visualização.
Eu posso fazer assim (desculpe, c # não é java, mas não é um problema ...):
private int iValue = 1234567890;
function void MyTest()
{
Intent oIntent = new Intent (this, typeof(Camera2Activity));
Bundle oBundle = new Bundle();
oBundle.PutInt("MYVALUE", iValue); //=> 1234567890
oIntent.PutExtras (oBundle);
iRequestCode = 1111;
StartActivityForResult (oIntent, 1111);
}
E EM SUA ATIVIDADE PARA RESULTADO
private int iValue = 0;
protected override void OnCreate(Bundle bundle)
{
Bundle oBundle = Intent.Extras;
if (oBundle != null)
{
iValue = oBundle.GetInt("MYVALUE", 0);
//=>1234567890
}
}
private void FinishActivity(bool bResult)
{
Intent oIntent = new Intent();
Bundle oBundle = new Bundle();
oBundle.PutInt("MYVALUE", iValue);//=>1234567890
oIntent.PutExtras(oBundle);
if (bResult)
{
SetResult (Result.Ok, oIntent);
}
else
SetResult(Result.Canceled, oIntent);
GC.Collect();
Finish();
}
FINALMENTE
protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
base.OnActivityResult (iRequestCode, oResultCode, oIntent);
iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}