salvar - savedinstancestate android




Salvando o estado de atividade do Android usando Salvar estado da instância (18)

Eu tenho trabalhado na plataforma Android SDK, e é um pouco claro como salvar o estado de um aplicativo. Então, dada essa pequena ferramenta do exemplo "Hello, Android":

package com.android.hello;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {

  private TextView mTextView = null;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mTextView = new TextView(this);

    if (savedInstanceState == null) {
       mTextView.setText("Welcome to HelloAndroid!");
    } else {
       mTextView.setText("Welcome back.");
    }

    setContentView(mTextView);
  }
}

Eu pensei que seria suficiente para o caso mais simples, mas sempre responde com a primeira mensagem, não importa como eu ando longe do aplicativo.

Tenho certeza de que a solução é tão simples quanto substituir o onPause ou algo assim, mas eu tenho onPause na documentação por 30 minutos ou mais e não encontrei nada óbvio.


Adicionando o LiveData (componentes de arquitetura do Android) ao seu projeto

adicione a seguinte dependência

implementation "android.arch.lifecycle:extensions:1.1.0"

O LiveData recebe um observador e o notifica sobre alterações de dados somente quando está no estado INICIADO ou RESUMIDO. A vantagem com o LiveData é que quando sua atividade entra em qualquer estado diferente de STARTED ou RESUMED, ele não chamará o método onChanged no observador .

private TextView mTextView;
private MutableLiveData<String> mMutableLiveData;

@Override
protected void onCreate(Bundle savedInstanceState) {
    mTextView = (TextView) findViewById(R.id.textView);
    mMutableLiveData = new MutableLiveData<>();
    mMutableLiveData.observe(this, new Observer<String>() {
        @Override
        public void onChanged(@Nullable String s) {
            mTextView.setText(s);
        }
    });

}

É necessário substituir onSaveInstanceState(Bundle savedInstanceState) e gravar os valores de estado do aplicativo que você deseja alterar para o parâmetro Bundle seguinte forma:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
  super.onSaveInstanceState(savedInstanceState);
  // Save UI state changes to the savedInstanceState.
  // This bundle will be passed to onCreate if the process is
  // killed and restarted.
  savedInstanceState.putBoolean("MyBoolean", true);
  savedInstanceState.putDouble("myDouble", 1.9);
  savedInstanceState.putInt("MyInt", 1);
  savedInstanceState.putString("MyString", "Welcome back to Android");
  // etc.
}

O Bundle é essencialmente uma maneira de armazenar um mapa NVP ("Pair de Nome-Valor"), e ele será passado para onCreate() e também onRestoreInstanceState() onde você onRestoreInstanceState() os valores da seguinte forma:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  // Restore UI state from the savedInstanceState.
  // This bundle has also been passed to onCreate.
  boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
  double myDouble = savedInstanceState.getDouble("myDouble");
  int myInt = savedInstanceState.getInt("MyInt");
  String myString = savedInstanceState.getString("MyString");
}

Você usaria normalmente essa técnica para armazenar valores de instância para seu aplicativo (seleções, texto não salvo, etc.).


Esta é uma clássica 'pegadinha' do desenvolvimento do Android. Há duas questões aqui:

  • Há um bug sutil no Android Framework que complica muito o gerenciamento de pilha de aplicativos durante o desenvolvimento, pelo menos em versões herdadas (não inteiramente certo se / quando / como foi corrigido). Eu vou discutir esse bug abaixo.
  • A maneira "normal" ou pretendida de gerenciar esse problema é, em si, bastante complicada com a dualidade de onPause / onResume e onSaveInstanceState / onRestoreInstanceState

Navegando em todos esses tópicos, eu suspeito que a maior parte do tempo os desenvolvedores estão falando sobre esses dois problemas diferentes simultaneamente ... daí toda a confusão e os relatos de "isso não funciona para mim".

Primeiro, para esclarecer o comportamento 'pretendido': onSaveInstance e onRestoreInstance são frágeis e apenas para estado transitório. O uso pretendido (afaict) é manipular a atividade recreativa quando o telefone é girado (mudança de orientação). Em outras palavras, o uso pretendido é quando sua Atividade ainda está logicamente 'no topo', mas ainda deve ser reinstanciada pelo sistema. O Bundle salvo não é mantido fora do processo / memory / gc, então você não pode realmente confiar nisso se sua atividade for para o segundo plano. Sim, talvez a memória da sua Atividade sobreviva à sua viagem para o fundo e escape do GC, mas isso não é confiável (nem é previsível).

Portanto, se você tiver um cenário em que haja um "progresso do usuário" significativo ou um estado que deva persistir entre "lançamentos" de seu aplicativo, a orientação é usar onPause e onResume. Você deve escolher e preparar uma loja persistente por conta própria.

MAS - há um bug muito confuso que complica tudo isso. Detalhes estão aqui:

http://code.google.com/p/android/issues/detail?id=2373

http://code.google.com/p/android/issues/detail?id=5277

Basicamente, se seu aplicativo for iniciado com o sinalizador SingleTask e, posteriormente, você iniciá-lo na tela inicial ou no menu inicializador, essa chamada subsequente criará uma NOVA tarefa ... você terá duas instâncias diferentes do seu aplicativo habitando a mesma pilha ... o que fica muito estranho muito rápido. Isso parece acontecer quando você inicia seu aplicativo durante o desenvolvimento (ou seja, do Eclipse ou Intellij), portanto, os desenvolvedores correm muito nisso. Mas também através de alguns dos mecanismos de atualização da loja de aplicativos (isso também afeta seus usuários).

Eu lutei com esses tópicos por horas antes de perceber que o meu problema principal era esse bug, não o comportamento pretendido do framework. Um ótimo writeup e solução alternativa (UPDATE: veja abaixo) parece ser do usuário @kaciula nesta resposta:

Comportamento da tecla de início

ATUALIZAÇÃO EM JUNHO DE 2013 : Meses depois, finalmente encontrei a solução "correta". Você não precisa gerenciar nenhum sinalizador startedApp com estado, você pode detectar isso a partir da estrutura e liberar adequadamente. Eu uso isso perto do começo do meu LauncherActivity.onCreate:

if (!isTaskRoot()) {
    Intent intent = getIntent();
    String action = intent.getAction();
    if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) {
        finish();
        return;
    }
}

Eu acho que encontrei a resposta. Deixe-me dizer o que eu fiz em palavras simples:

Suponha que eu tenha duas atividades, activity1 e activity2 e eu esteja navegando de activity1 para activity2 (já fiz alguns trabalhos em activity2) e novamente para a atividade 1, clicando em um botão em activity1. Agora, neste estágio, eu queria voltar para a atividade2 e quero ver minha atividade2 na mesma condição quando saí da atividade2.

Para o cenário acima, o que fiz foi que no manifesto fiz algumas alterações como esta:

<activity android:name=".activity2"
          android:alwaysRetainTaskState="true"      
          android:launchMode="singleInstance">
</activity>

E na atividade1 no botão clique no evento que fiz assim:

Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.setClassName(this,"com.mainscreen.activity2");
startActivity(intent);

E na atividade2 no botão clique em evento eu fiz assim:

Intent intent=new Intent();
intent.setClassName(this,"com.mainscreen.activity1");
startActivity(intent);

Agora, o que acontecerá é que, sejam quais forem as mudanças que tenhamos feito na atividade2, não serão perdidas, e poderemos ver a atividade2 no mesmo estado que deixamos anteriormente.

Eu acredito que esta é a resposta e isso funciona bem para mim. Corrija-me se eu estiver enganado.


O savedInstanceState é apenas para salvar o estado associado a uma instância atual de uma Activity, por exemplo, informações atuais de navegação ou seleção, para que, se o Android destruir e recriar uma Activity, possa voltar como era antes. Veja a documentação para onCreate e onSaveInstanceState

Para um estado mais longo, considere usar um banco de dados SQLite, um arquivo ou preferências. Veja Salvando Estado Persistente .


O estado de poupança é um kludge na melhor das hipóteses, tanto quanto eu estou preocupado. Se você precisar salvar dados persistentes, basta usar um SQLite dados SQLite . O Android torna o SOOO fácil.

Algo assim:

import java.util.Date;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class dataHelper {

    private static final String DATABASE_NAME = "autoMate.db";
    private static final int DATABASE_VERSION = 1;

    private Context context;
    private SQLiteDatabase db;
    private OpenHelper oh ;

    public dataHelper(Context context) {
        this.context = context;
        this.oh = new OpenHelper(this.context);
        this.db = oh.getWritableDatabase();
    }

    public void close()
    {
        db.close();
        oh.close();
        db = null;
        oh = null;
        SQLiteDatabase.releaseMemory();
    }


    public void setCode(String codeName, Object codeValue, String codeDataType)
    {
        Cursor codeRow = db.rawQuery("SELECT * FROM code WHERE codeName = '"+  codeName + "'", null);
        String cv = "" ;

        if (codeDataType.toLowerCase().trim().equals("long") == true)
        {
            cv = String.valueOf(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("int") == true)
        {
            cv = String.valueOf(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("date") == true)
        {
            cv = String.valueOf(((Date)codeValue).getTime());
        }
        else if (codeDataType.toLowerCase().trim().equals("boolean") == true)
        {
            String.valueOf(codeValue);
        }
        else
        {
            cv = String.valueOf(codeValue);
        }

        if(codeRow.getCount() > 0) //exists-- update
        {
            db.execSQL("update code set codeValue = '" + cv +
                "' where codeName = '" + codeName + "'");
        }
        else // does not exist, insert
        {
            db.execSQL("INSERT INTO code (codeName, codeValue, codeDataType) VALUES(" +
                    "'" + codeName + "'," +
                    "'" + cv + "'," +
                    "'" + codeDataType + "')" );
        }
    }

    public Object getCode(String codeName, Object defaultValue)
    {
        //Check to see if it already exists
        String codeValue = "";
        String codeDataType = "";
        boolean found = false;
        Cursor codeRow  = db.rawQuery("SELECT * FROM code WHERE codeName = '"+  codeName + "'", null);
        if (codeRow.moveToFirst())
        {
            codeValue = codeRow.getString(codeRow.getColumnIndex("codeValue"));
            codeDataType = codeRow.getString(codeRow.getColumnIndex("codeDataType"));
            found = true;
        }

        if (found == false)
        {
            return defaultValue;
        }
        else if (codeDataType.toLowerCase().trim().equals("long") == true)
        {
            if (codeValue.equals("") == true)
            {
                return (long)0;
            }
            return Long.parseLong(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("int") == true)
        {
            if (codeValue.equals("") == true)
            {
                return (int)0;
            }
            return Integer.parseInt(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("date") == true)
        {
            if (codeValue.equals("") == true)
            {
                return null;
            }
            return new Date(Long.parseLong(codeValue));
        }
        else if (codeDataType.toLowerCase().trim().equals("boolean") == true)
        {
            if (codeValue.equals("") == true)
            {
                return false;
            }
            return Boolean.parseBoolean(codeValue);
        }
        else
        {
            return (String)codeValue;
        }
    }


    private static class OpenHelper extends SQLiteOpenHelper {

        OpenHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE IF  NOT EXISTS code" +
            "(id INTEGER PRIMARY KEY, codeName TEXT, codeValue TEXT, codeDataType TEXT)");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
}

Uma simples ligação depois disso

dataHelper dh = new dataHelper(getBaseContext());
String status = (String) dh.getCode("appState", "safetyDisabled");
Date serviceStart = (Date) dh.getCode("serviceStartTime", null);
dh.close();
dh = null;

onSaveInstanceState()para dados transitórios (restaurados em onCreate()/ onRestoreInstanceState()), onPause()para dados persistentes (restaurados em onResume()). De recursos técnicos do Android:

onSaveInstanceState () é chamado pelo Android se a atividade está sendo interrompida e pode ser eliminada antes de ser retomada! Isso significa que deve armazenar qualquer estado necessário para reinicializar na mesma condição quando a atividade for reiniciada. É a contrapartida do método onCreate () e, na verdade, o Bundle savedInstanceState passado para onCreate () é o mesmo Bundle que você constrói como outState no método onSaveInstanceState ().

onPause () e onResume () também são métodos complementares. onPause () é sempre chamado quando a Activity termina, mesmo que tenhamos instigado isso (com uma chamada finish () por exemplo). Usaremos isso para salvar a nota atual de volta no banco de dados. A boa prática é liberar todos os recursos que podem ser liberados durante um onPause (), para ocupar menos recursos quando no estado passivo.


onSaveInstanceState é chamado quando o sistema precisa de memória e mata um aplicativo. Não é chamado quando o usuário apenas fecha o aplicativo. Então, eu acho que o estado do aplicativo também deve ser salvo em onPause Ele deve ser salvo em algum armazenamento persistente, como Preferences ou Sqlite


Código Kotlin:

Salve :

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState.apply {
        putInt("intKey", 1)
        putString("stringKey", "String Value")
        putParcelable("parcelableKey", parcelableObject)
    })
}

e depois em onCreate()ouonRestoreInstanceState()

    val restoredInt = savedInstanceState?.getInt("intKey") ?: 1 //default int
    val restoredString = savedInstanceState?.getString("stringKey") ?: "default string"
    val restoredParcelable = savedInstanceState?.getParcelable<ParcelableClass>("parcelableKey") ?: ParcelableClass() //default parcelable

Adicionar valores padrão se você não quiser ter opções


Enquanto isso eu faço em geral não mais uso

Bundle savedInstanceState & Co

o ciclo ao vivo é para a maioria das atividades muito complicado e desnecessário. E google afirma-se, não é mesmo confiável.

Meu jeito é salvar as alterações imediatamente nas preferências

 SharedPreferences p;
 p.edit().put(..).commit()

de alguma forma, o SharedPreferences funciona de maneira similar ao Bundles. E naturalmente e a princípio tais valores têm que ser vermelhos das preferências.

No caso de dados complexos, você pode usar o Sqlite em vez de usar preferências.

Ao aplicar esse conceito, a atividade continua a usar o último estado salvo, independentemente de ter sido uma abertura inicial com reinicializações no meio ou uma reabertura devido à pilha de trás.


Quando uma atividade é criada, o método onCreate () é chamado.

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

savedInstanceState é um objeto da classe Bundle que é nulo pela primeira vez, mas contém valores quando é recriado. Para salvar o estado da Atividade, você deve sobrescrever onSaveInstanceState ().

   @Override
    protected void onSaveInstanceState(Bundle outState) {
      outState.putString("key","Welcome Back")
        super.onSaveInstanceState(outState);       //save state
    }

coloque seus valores no objeto "outState" Bundle como outState.putString ("key", "Welcome Back") e salve chamando super. Quando a atividade será destruída, seu estado será salvo no objeto Bundle e poderá ser restaurado após a recriação em onCreate () ou onRestoreInstanceState (). O pacote recebido em onCreate () e onRestoreInstanceState () é o mesmo.

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

          //restore activity's state
         if(savedInstanceState!=null){
          String reStoredString=savedInstanceState.getString("key");
            }
    }

ou

  //restores activity's saved state
 @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
      String restoredMessage=savedInstanceState.getString("key");
    }

Agora o Android fornece ViewModels para salvar o estado, você deve tentar usar isso em vez de saveInstanceState.


Embora a resposta aceita esteja correta, existe um método mais rápido e fácil de salvar o estado de atividade no Android usando uma biblioteca chamada Icepick . O Icepick é um processador de anotações que cuida de todo o código padrão utilizado para salvar e restaurar o estado para você.

Fazendo algo assim com o Icepick:

class MainActivity extends Activity {
  @State String username; // These will be automatically saved and restored
  @State String password;
  @State int age;

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Icepick.restoreInstanceState(this, savedInstanceState);
  }

  @Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Icepick.saveInstanceState(this, outState);
  }
}

É o mesmo que fazer isso:

class MainActivity extends Activity {
  String username;
  String password;
  int age;

  @Override
  public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString("MyString", username);
    savedInstanceState.putString("MyPassword", password);
    savedInstanceState.putInt("MyAge", age); 
    /* remember you would need to actually initialize these variables before putting it in the
    Bundle */
  }

  @Override
  public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    username = savedInstanceState.getString("MyString");
    password = savedInstanceState.getString("MyPassword");
    age = savedInstanceState.getInt("MyAge");
  }
}

O Icepick funcionará com qualquer objeto que salve seu estado com um Bundle.


Meu problema era que eu precisava de persistência apenas durante a vida útil da aplicação (ou seja, uma única execução, incluindo iniciar outras subatividades dentro do mesmo aplicativo e girar o dispositivo, etc.). Eu tentei várias combinações das respostas acima, mas não consegui o que queria em todas as situações. No final, o que funcionou para mim foi obter uma referência ao savedInstanceState durante o onCreate:

mySavedInstanceState=savedInstanceState;

e usar isso para obter o conteúdo da minha variável quando eu precisasse, ao longo das linhas de:

if (mySavedInstanceState !=null) {
   boolean myVariable = mySavedInstanceState.getBoolean("MyVariable");
}

Eu uso onSaveInstanceStatee onRestoreInstanceStatecomo sugerido acima, mas eu acho que eu poderia também ou, alternativamente, usar o meu método para salvar a variável quando ela muda (por exemplo, usando putBoolean)


Os métodos onSaveInstanceState(bundle)e onRestoreInstanceState(bundle)são úteis para persistência de dados apenas durante a rotação da tela (alteração de orientação).
Eles não são ainda bem enquanto alternar entre aplicações (uma vez que o onSaveInstanceState()método é chamado, mas onCreate(bundle)e onRestoreInstanceState(bundle)não é invocado novamente.
Para mais preferências uso compartilhado persistência. Ler este artigo


Para ajudar a reduzir o clichê, uso o seguinte interfacee classpara ler / gravar em um Bundleestado de instância para salvar.

Primeiro, crie uma interface que será usada para anotar suas variáveis ​​de instância:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
        ElementType.FIELD
})
public @interface SaveInstance {

}

Em seguida, crie uma classe em que a reflexão será usada para salvar valores no pacote:

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;

import java.io.Serializable;
import java.lang.reflect.Field;

/**
 * Save and load fields to/from a {@link Bundle}. All fields should be annotated with {@link
 * SaveInstance}.</p>
 */
public class Icicle {

    private static final String TAG = "Icicle";

    /**
     * Find all fields with the {@link SaveInstance} annotation and add them to the {@link Bundle}.
     *
     * @param outState
     *         The bundle from {@link Activity#onSaveInstanceState(Bundle)} or {@link
     *         Fragment#onSaveInstanceState(Bundle)}
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @see #load(Bundle, Object)
     */
    public static void save(Bundle outState, Object classInstance) {
        save(outState, classInstance, classInstance.getClass());
    }

    /**
     * Find all fields with the {@link SaveInstance} annotation and add them to the {@link Bundle}.
     *
     * @param outState
     *         The bundle from {@link Activity#onSaveInstanceState(Bundle)} or {@link
     *         Fragment#onSaveInstanceState(Bundle)}
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @param baseClass
     *         Base class, used to get all superclasses of the instance.
     * @see #load(Bundle, Object, Class)
     */
    public static void save(Bundle outState, Object classInstance, Class<?> baseClass) {
        if (outState == null) {
            return;
        }
        Class<?> clazz = classInstance.getClass();
        while (baseClass.isAssignableFrom(clazz)) {
            String className = clazz.getName();
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(SaveInstance.class)) {
                    field.setAccessible(true);
                    String key = className + "#" + field.getName();
                    try {
                        Object value = field.get(classInstance);
                        if (value instanceof Parcelable) {
                            outState.putParcelable(key, (Parcelable) value);
                        } else if (value instanceof Serializable) {
                            outState.putSerializable(key, (Serializable) value);
                        }
                    } catch (Throwable t) {
                        Log.d(TAG, "The field '" + key + "' was not added to the bundle");
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

    /**
     * Load all saved fields that have the {@link SaveInstance} annotation.
     *
     * @param savedInstanceState
     *         The saved-instance {@link Bundle} from an {@link Activity} or {@link Fragment}.
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @see #save(Bundle, Object)
     */
    public static void load(Bundle savedInstanceState, Object classInstance) {
        load(savedInstanceState, classInstance, classInstance.getClass());
    }

    /**
     * Load all saved fields that have the {@link SaveInstance} annotation.
     *
     * @param savedInstanceState
     *         The saved-instance {@link Bundle} from an {@link Activity} or {@link Fragment}.
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @param baseClass
     *         Base class, used to get all superclasses of the instance.
     * @see #save(Bundle, Object, Class)
     */
    public static void load(Bundle savedInstanceState, Object classInstance, Class<?> baseClass) {
        if (savedInstanceState == null) {
            return;
        }
        Class<?> clazz = classInstance.getClass();
        while (baseClass.isAssignableFrom(clazz)) {
            String className = clazz.getName();
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(SaveInstance.class)) {
                    String key = className + "#" + field.getName();
                    field.setAccessible(true);
                    try {
                        Object fieldVal = savedInstanceState.get(key);
                        if (fieldVal != null) {
                            field.set(classInstance, fieldVal);
                        }
                    } catch (Throwable t) {
                        Log.d(TAG, "The field '" + key + "' was not retrieved from the bundle");
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

}

Exemplo de uso:

public class MainActivity extends Activity {

    @SaveInstance
    private String foo;

    @SaveInstance
    private int bar;

    @SaveInstance
    private Intent baz;

    @SaveInstance
    private boolean qux;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Icicle.load(savedInstanceState, this);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Icicle.save(outState, this);
    }

}

Nota: Este código foi adaptado de um projeto de biblioteca chamado AndroidAutowire que é licenciado sob a licença MIT .


Para responder a pergunta original diretamente. savedInstancestate é null porque sua atividade nunca está sendo recriada.

Sua atividade só será recriada com um pacote de estado quando:

  • Alterações na configuração, como alterar a orientação ou a linguagem do telefone, o que pode exigir que uma nova instância de atividade seja criada.
  • Você retorna ao aplicativo do segundo plano depois que o sistema operacional destruiu a atividade.

O Android destruirá as atividades em segundo plano quando estiver sob pressão de memória ou depois de ficar em segundo plano por um longo período de tempo.

Ao testar seu exemplo de hello world, há algumas maneiras de sair e retornar à Activity.

  • Quando você pressiona o botão Voltar, a atividade é concluída. O relançamento do aplicativo é uma nova instância. Você não está retomando do fundo.
  • Quando você pressiona o botão de início ou usa o alternador de tarefas, a Atividade fica em segundo plano. Ao navegar de volta para o aplicativo, onCreate só será chamado se a Atividade tiver que ser destruída.

Na maioria dos casos, se você pressionar a página inicial e ativar o aplicativo novamente, a atividade não precisará ser recriada. Já existe na memória, então onCreate () não será chamado.

Existe uma opção em Configurações -> Opções do desenvolvedor chamada "Não manter atividades". Quando ativado, o Android sempre destruirá as atividades e as recriará quando estiverem em segundo plano. Essa é uma ótima opção para deixar ativada durante o desenvolvimento porque simula o pior cenário possível. (Um dispositivo de baixa memória reciclar suas atividades o tempo todo).

As outras respostas são valiosas, pois ensinam as maneiras corretas de armazenar o estado, mas não senti que elas realmente respondiam PORQUE seu código não estava funcionando da maneira esperada.


Realmente onSaveInstancechamar quando a atividade vai para o fundo

Citação da documentação: "o método onSaveInstanceState(Bundle)é chamado antes de colocar a atividade em um estado de segundo plano"





application-state