onSaveInstanceState () e onRestoreInstanceState ()

138

Estou tentando salvar e restaurar o estado de um Activityusando 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?

BlaBRA
fonte
1
@Nitin: obrigado por compartilhar o link ... isso esclareceu algumas coisas para mim +1
Taliadon
2
@NitinBansal o link está morto.
ashishdhiman2007

Respostas:

191

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");
  }
}
Robert
fonte
2
o problema é que uso startActivity para retornar à atividade A. Ao retornar à atividade B, o objeto é um icicle nulo.
BlaBRA
5
Se bem entendi, é isso que você está fazendo: em B, você chama startActivity (A). Então, de A, você chama terminar () para voltar para B. Certo? Nesse caso, sua primeira atividade, B, não terá sido destruída e nem onCreate () nem onRestoreInstanceState () serão chamados. Esses métodos são chamados apenas quando necessários, ou seja, quando uma atividade foi destruída e precisa ser recriada pelo sistema.
Robert
4
Devo acrescentar que sua primeira atividade, B, pode ser destruída devido a condições de pouca memória. Isso irá acionar onCreate e onRestoreInstanceState.
Robert
1
erikb, sim, a atividade B será retomada ou, caso o sistema operacional a tenha recuperado, recriado e reiniciado.
Robert
1
Oh, é por isso
Al Lelopath
149

onRestoreInstanceState()é chamado apenas ao recriar a atividade depois de eliminada pelo sistema operacional. Tal situação acontece quando:

  • a orientação das mudanças do dispositivo (sua atividade é destruída e recriada).
  • há outra atividade na frente da sua e em algum momento o SO mata sua atividade para liberar memória (por exemplo). Na próxima vez que você iniciar sua atividade, onRestoreInstanceState () será chamado.

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 Activitye seja esperado que alguém crie uma subclasse de sua subclasse.

Ognyan
fonte
3
sim, isso parece estar certo, mas é uma merda. imo, também deve ser executado ao retornar à atividade de outra atividade. há muitas situações em que você precisa disso.
masi de
4
@masi já existem outros métodos invocados na Activity quando o usuário retorna a ela (de outra atividade). O onSave / RestoreInstanceState () é usado para outro propósito específico, é isso.
superjos
8

O estado em que você salva onSaveInstanceState()está disponível posteriormente na onCreate()invocação do método. Portanto, use onCreate(e seu Bundleparâmetro) para restaurar o estado de sua atividade.

Konstantin Burov
fonte
4

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.

sotrh
fonte
3

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.

user1771286
fonte
1
onRestoreInstanceState () será chamado, mesmo se você não armazenar nada em OnSaveInstanceState ()
abh22ishek
3

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.

zumbido
fonte
2

Acho que este tópico era bastante antigo. Acabei de mencionar outro caso, que onSaveInstanceState()também será chamado, é quando você liga Activity.moveTaskToBack(boolean nonRootActivity).

macio.Jun
fonte
1

Se você estiver lidando com as mudanças de orientação da atividade com android:configChanges="orientation|screenSize"e onConfigurationChanged(Configuration newConfig), onRestoreInstanceState()não será chamado.

Rajkiran
fonte
1

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.

Ashutosh Srivastava
fonte
1

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 :

insira a descrição da imagem aqui

insira a descrição da imagem aqui

IMO, esta é uma forma mais clara do que verificar na onCreate, e se encaixa melhor com o princípio de responsabilidade única.

Teoman shipahi
fonte
0

No meu caso, onRestoreInstanceStatefoi 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.

elvitucho
fonte
0

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."

https://developer.android.com/reference/android/view/View.html#onRestoreInstanceState(android.os.Parcelable)

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.

Ben Scannell
fonte
0

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
}
EDynamic90
fonte