Zapisywanie stanu aktywności Androida za pomocą Zapisz stan wystąpienia

Pracowałem na platformie Android SDK i jest trochę niejasne, jak zapisać stan aplikacji. Tak więc, biorąc pod uwagę to drobne przeprojektowanie przykładu "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);
  }
}

Myślałem, że wystarczy na najprostszy przypadek, ale zawsze odpowiada pierwszą wiadomością, bez względu na to, jak odchodzę od aplikacji.

Jestem pewien, że rozwiązanie jest tak proste, jak nadpisanie onPause Czy coś w tym stylu, ale grzebałem w dokumentacji przez jakieś 30 minut. i nie znalazłem niczego oczywistego.

Author: Taryn, 2008-09-30

27 answers

Musisz nadpisać onSaveInstanceState(Bundle savedInstanceState) i zapisać wartości stanu aplikacji, które chcesz zmienić na parametr Bundle w następujący sposób:

@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.
}

Pakiet jest zasadniczo sposobem przechowywania mapy NVP ("para nazwa-wartość") i zostanie przekazany do onCreate(), a także onRestoreInstanceState(), gdzie można wyodrębnić wartości w następujący sposób:

@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");
}

Zazwyczaj używa się tej techniki do przechowywania wartości instancji aplikacji (selekcji, niezapisanego tekstu itp.).

 2316
Author: Reto Meier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-07 10:11:08

savedInstanceState służy tylko do zapisywania stanu związanego z bieżącą instancją aktywności, na przykład bieżącą nawigacją lub informacjami o wyborze, tak że jeśli Android zniszczy i odtworzy aktywność, może wrócić tak, jak wcześniej. Zobacz dokumentację dla onCreate oraz onSaveInstanceState

Aby uzyskać bardziej długotrwały stan, rozważ użycie bazy danych SQLite, pliku lub preferencji. Zobacz Zapisywanie Stanu Trwałego .

 385
Author: Dave L.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-13 00:24:16

Zauważ, że jest to nie bezpieczne w użyciu onSaveInstanceState i onRestoreInstanceState dla danych trwałych , zgodnie z dokumentacją Stanów aktywności w http://developer.android.com/reference/android/app/Activity.html .

Dokument stwierdza (w sekcji "cykl życia działalności"):

Należy pamiętać, że ważne jest, aby zapisać dane trwałe w onPause() zamiast z onSaveInstanceState(Bundle) ponieważ później nie jest częścią wywołania zwrotne cyklu życia, więc nie będzie wywoływane w każdej sytuacji zgodnie z opisem w swojej dokumentacji.

Innymi słowy, umieść swój kod zapisu / przywracania dla trwałych danych w onPause() i onResume()!

EDIT : dla dalszych wyjaśnień, oto onSaveInstanceState() dokumentacja:

[[9]}metoda ta jest wywoływana zanim czynność może zostać zabita tak, że gdy w przyszłości może przywrócić swój stan. Na przykład, jeśli ćwiczenie B jest uruchamiane przed ćwiczeniem A, a w niektórych punkt działanie A jest zabijane w celu odzyskania zasobów, działanie A będzie miało możliwość zapisania aktualnego stanu interfejsu użytkownika za pomocą tego metoda tak, aby po powrocie użytkownika do aktywności A stan interfejs użytkownika można przywrócić poprzez onCreate(Bundle) lub onRestoreInstanceState(Bundle).
 373
Author: Steve Moseley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-24 23:04:27

Mój kolega napisał artykuł wyjaśniający stan aplikacji na urządzeniach z Androidem, w tym wyjaśnienia dotyczące cyklu życia aktywności i informacji o stanie, jak przechowywać informacje o stanie i zapisywać do stanu Bundle i SharedPreferences i spójrz tutaj .

Artykuł obejmuje trzy podejścia:

Przechowuj lokalne dane sterujące varible/UI przez cały okres życia aplikacji (tj. tymczasowo) przy użyciu pakietu stanu instancji

[Code sample – Store State in State Bundle]
@Override
public void onSaveInstanceState(Bundle savedInstanceState) 
{
  // Store UI state to the savedInstanceState.
  // This bundle will be passed to onCreate on next call.  EditText txtName = (EditText)findViewById(R.id.txtName);
  String strName = txtName.getText().toString();

  EditText txtEmail = (EditText)findViewById(R.id.txtEmail);
  String strEmail = txtEmail.getText().toString();

  CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC);
  boolean blnTandC = chkTandC.isChecked();

  savedInstanceState.putString(“Name”, strName);
  savedInstanceState.putString(“Email”, strEmail);
  savedInstanceState.putBoolean(“TandC”, blnTandC);

  super.onSaveInstanceState(savedInstanceState);
}

Przechowuj lokalne dane sterujące varible / UI między aplikacją instancje (IE permanentnie) za pomocą współdzielonych preferencji

[Code sample – Store State in SharedPreferences]
@Override
protected void onPause() 
{
  super.onPause();

  // Store values between instances here
  SharedPreferences preferences = getPreferences(MODE_PRIVATE);
  SharedPreferences.Editor editor = preferences.edit();  // Put the values from the UI
  EditText txtName = (EditText)findViewById(R.id.txtName);
  String strName = txtName.getText().toString();

  EditText txtEmail = (EditText)findViewById(R.id.txtEmail);
  String strEmail = txtEmail.getText().toString();

  CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC);
  boolean blnTandC = chkTandC.isChecked();

  editor.putString(“Name”, strName); // value to store
  editor.putString(“Email”, strEmail); // value to store
  editor.putBoolean(“TandC”, blnTandC); // value to store    
  // Commit to storage
  editor.commit();
}

Utrzymywanie żywych instancji obiektów w pamięci pomiędzy aktywnościami w czasie życia aplikacji przy użyciu zachowanej instancji innej niż konfiguracja

[Code sample – store object instance]
private cMyClassType moInstanceOfAClass;// Store the instance of an object
@Override
public Object onRetainNonConfigurationInstance() 
{
  if (moInstanceOfAClass != null) // Check that the object exists
      return(moInstanceOfAClass);
  return super.onRetainNonConfigurationInstance();
}
 174
Author: Martin Belcher - Eigo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-18 09:58:31

Jest to klasyczna' gotcha ' rozwoju Androida. Są tu dwie kwestie:

  • istnieje subtelny błąd systemu Android, który znacznie komplikuje zarządzanie stosem aplikacji podczas tworzenia aplikacji, przynajmniej w starszych wersjach (nie do końca wiem, czy/kiedy / jak został naprawiony). Omówię ten błąd poniżej.
  • "normalny" lub zamierzony sposób radzenia sobie z tym problemem jest, sam w sobie, dość skomplikowany z dualnością onPause/onResume i onSaveInstanceState / onRestoreInstanceState

Przeglądając wszystkie te wątki, podejrzewam, że większość czasu deweloperzy mówią o tych dwóch różnych sprawach jednocześnie ... stąd całe zamieszanie i doniesienia o "to nie działa dla mnie".

Po pierwsze, aby wyjaśnić "zamierzone" zachowanie: onSaveInstance i onRestoreInstance są kruche i tylko dla stanu przejściowego. Zamierzonym zastosowaniem (afaict) jest obsługa rekreacji aktywnej po obróceniu telefonu (zmiana orientacji). Innymi słowy, zamierzone użycie jest wtedy, gdy Twoja aktywność jest nadal logicznie "na szczycie", ale nadal musi zostać ponownie potwierdzona przez system. Zapisany Pakiet nie jest utrzymywany poza procesem / pamięcią / gc, więc nie możesz na tym polegać, jeśli Twoja aktywność przechodzi w tło. Tak, być może pamięć Twojej aktywności przetrwa podróż w tło i ucieczkę z GC, ale nie jest to wiarygodne (ani przewidywalne).

Więc jeśli masz scenariusz, w którym jest znaczące "postępy użytkownika" lub stan, który powinien być utrzymywany pomiędzy "uruchomieniami" Twojej aplikacji, wskazówki dotyczą korzystania z onPause i onResume. Musisz sam wybrać i przygotować trwały sklep.

Ale-jest bardzo mylący błąd, który komplikuje to wszystko. Szczegóły są tutaj:

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

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

Zasadniczo, jeśli twój wniosek jest uruchamiany z flagą SingleTask, a później uruchamiasz go z ekranu głównego lub menu launchera, a następnie to kolejne wywołanie utworzy nowe zadanie ... będziesz mieć dwie różne instancje aplikacji zamieszkujące ten sam stos ... co robi się bardzo dziwne, bardzo szybko. Wydaje się, że dzieje się tak, gdy uruchamiasz swoją aplikację podczas rozwoju (np. z Eclipse lub Intellij), więc deweloperzy często na to wpadają. Ale także poprzez niektóre mechanizmy aktualizacji app store (tak więc wpływa użytkowników, jak również).

Zmagałem się z tymi wątkami godzinami, zanim zdałem sobie sprawę, że moim głównym problemem był ten błąd, a nie zamierzone zachowanie frameworka. Wielki writeup i workaround (UPDATE: patrz niżej) wydaje się być od użytkownika @kaciula w tej odpowiedzi:

Home key press behavior

Aktualizacja czerwiec 2013 : miesiące później, w końcu znalazłem "poprawne" rozwiązanie. Nie musisz samodzielnie zarządzać flagami stateful startedApp, możesz / align = "left" / Używam tego na początku mojej pracy."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;
    }
}
 129
Author: Mike Repass,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:34

onSaveInstanceState jest wywoływany, gdy system potrzebuje pamięci i zabija aplikację. Nie jest wywoływana, gdy użytkownik po prostu zamyka aplikację. Więc myślę, że stan aplikacji powinien być również zapisany w {[1] } powinien być zapisany w jakimś trwałym magazynie, takim jak Preferences lub Sqlite

 70
Author: Fedor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-20 14:07:53

Obie metody są użyteczne i ważne i obie najlepiej nadają się do różnych scenariuszy:

  1. użytkownik kończy aplikację i otwiera ją ponownie w późniejszym terminie, ale aplikacja musi ponownie załadować dane z ostatniej sesji-wymaga to trwałego przechowywania, takiego jak użycie SQLite.
  2. użytkownik przełącza aplikację, a następnie wraca do oryginału i chce wrócić do miejsca, w którym został przerwany - Zapisz i przywróć dane pakietu (takie jak dane stanu aplikacji) w onSaveInstanceState() i onRestoreInstanceState() jest zazwyczaj odpowiedni.

Jeśli zapisujesz dane Stanu w sposób trwały, można je przeładować w onResume() lub onCreate() (lub w rzeczywistości w dowolnym wywołaniu cyklu życia). Takie zachowanie może, ale nie musi być pożądane. Jeśli przechowujesz go w pakiecie w InstanceState, to jest przejściowy i nadaje się tylko do przechowywania danych do użycia w tej samej sesji użytkownika (używam terminu session luźno), ale nie między "sesjami".

Nie jest tak, że jedno podejście jest lepsze od drugiego, jak wszystko, to jest po prostu ważne, aby zrozumieć, jakiego zachowania potrzebujesz i wybrać najbardziej odpowiednie podejście.

 59
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-12 23:34:47

Stan ratowania jest dla mnie kludżą. Jeśli chcesz zapisać trwałe DANE, po prostu użyj SQLite bazy danych. Android sprawia, że SOOO spokojnie.

Coś takiego:

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) {
        }
    }
}

A simple call after that

dataHelper dh = new dataHelper(getBaseContext());
String status = (String) dh.getCode("appState", "safetyDisabled");
Date serviceStart = (Date) dh.getCode("serviceStartTime", null);
dh.close();
dh = null;
 50
Author: Mike A.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-21 22:08:12

Chyba znalazłem odpowiedź. Pozwól mi powiedzieć, co zrobiłem w prostych słowach:

Załóżmy, że mam dwie czynności, aktywność1 i aktywność2 i przechodzę od aktywność1 do aktywność2 (wykonałem kilka prac w aktywność2) i ponownie wracam do aktywności 1, klikając przycisk w aktywność1. Teraz na tym etapie chciałem wrócić do activity2 i chcę zobaczyć moją activity2 w tym samym stanie, kiedy ostatni raz opuściłem activity2.

Dla powyższego scenariusza zrobiłem to, że w manifest wprowadziłem takie zmiany:

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

A w aktywności1 na przycisku kliknij Zdarzenie zrobiłem tak:

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

A w activity2 na przycisku click event zrobiłem tak:

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

Teraz nastąpi to, że jakiekolwiek zmiany, które wprowadziliśmy w activity2, nie zostaną utracone i będziemy mogli oglądać activity2 w tym samym stanie, w jakim opuściliśmy wcześniej.

Wierzę, że to jest Odpowiedź i to działa dobrze dla mnie. Popraw mnie, jeśli się mylę.

 49
Author: roy mathew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-31 19:01:15

Odtwarzanie aktywności

Istnieje kilka scenariuszy, w których Twoja aktywność jest niszczona z powodu normalnego zachowania aplikacji, na przykład gdy użytkownik naciśnie przycisk Wstecz lub Twoja aktywność sygnalizuje własne zniszczenie przez wywołanie finish(). System może również zniszczyć twoją aktywność, jeśli jest ona obecnie zatrzymana i nie była używana przez długi czas lub działanie na pierwszym planie wymaga więcej zasobów, więc system musi zamknąć procesy w tle, aby odzyskać pamięć.

Kiedy twoja activity jest niszczona, ponieważ użytkownik naciska Wstecz lub activity Kończy się, systemowa koncepcja tej instancji Activity przepada na zawsze, ponieważ zachowanie wskazuje, że aktywność nie jest już potrzebna. Jeśli jednak system zniszczy aktywność z powodu ograniczeń systemowych (a nie normalnego zachowania aplikacji), to chociaż rzeczywistą instancję aktywności zniknie, system zapamiętuje, że istniała w taki sposób, że jeśli użytkownik powróci do niej, system utworzy nową instancję aktywności korzystanie z zestawu zapisanych danych, które opisują stan aktywności, gdy była destroyed. Zapisane dane, których system używa do przywrócenia poprzedniego stanu, nazywane są "stanem instancji" i są zbiorem par klucz-wartość przechowywanych w obiekcie Bundle.

Aby zapisać dodatkowe dane o stanie aktywności, musisz nadpisać metodę wywołania zwrotnego onSaveInstanceState (). System wywołuje tę metodę, gdy użytkownik opuszcza Twoją aktywność i przekazuje jej obiekt Bundle, który zostanie zapisany w Zdarzenie, w którym Twoja aktywność zostanie niespodziewanie zniszczona. Jeśli system musi później odtworzyć instancję activity, przekazuje ten sam obiekt Bundle zarówno metodom onRestoreInstanceState(), jak i onCreate(). Tutaj wpisz opis obrazka

Gdy system zaczyna zatrzymywać Twoją aktywność, wywołuje onSaveInstanceState() (1), dzięki czemu możesz określić dodatkowe dane stanu, które chcesz zapisać na wypadek, gdyby instancja aktywności musiała zostać odtworzona. Jeśli aktywność zostanie zniszczona i ta sama instancja musi zostać odtworzona, system przekazuje dane stanu zdefiniowane w (1) do metody onCreate() (2) i metody onRestoreInstanceState() (3).

Zapisz Swój Activity Stan

Gdy Twoja aktywność zaczyna się zatrzymywać, system wywołuje onSaveInstanceState(), aby Twoja aktywność mogła zapisać informacje o stanie za pomocą Kolekcji par klucz-wartość. Domyślna implementacja tej metody zapisuje informacje o stanie hierarchii widoków aktywności, takie jak tekst w widżecie EditText lub pozycja przewijania ListView.

Aby zapisać dodatkowe informacje o stanie dla Twoja aktywność, musisz zaimplementować onSaveInstanceState() i dodać pary klucz-wartość do obiektu Bundle. Na przykład:

  static final String STATE_SCORE = "playerScore";
  static final String STATE_LEVEL = "playerLevel";

  @Override
  public void onSaveInstanceState(Bundle savedInstanceState) {
  // Save the user's current game state
  savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
  savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);

  // Always call the superclass so it can save the view hierarchy state
  super.onSaveInstanceState(savedInstanceState);
}

Uwaga: zawsze wywołaj implementację klasy nadrzędnej onSaveInstanceState(), aby Domyślna implementacja mogła zapisać stan hierarchii widoku.

Przywróć Swój Activity Stan

Gdy Twoja aktywność zostanie odtworzona po jej wcześniejszym zniszczeniu, możesz odzyskać zapisany stan z pakietu, który system przekazuje Twoją aktywność. Zarówno onCreate() jak i onRestoreInstanceState() metody wywołania zwrotnego otrzymują tę samą Bundle, która zawiera informacje o stanie instancji.

Ponieważ metoda onCreate() jest wywoływana, czy system tworzy nową instancję Twojej aktywności, czy też odtwarza poprzednią, musisz sprawdzić, czy pakiet stanu jest null, zanim spróbujesz go odczytać. Jeżeli jest null, wtedy system tworzy nową instancję aktywności, zamiast przywracać poprzednią, która została zniszczona.

Na przykład, oto jak można przywrócić niektóre państwo dane w onCreate():

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState); // Always call the superclass first

 // Check whether we're recreating a previously destroyed instance
 if (savedInstanceState != null) {
    // Restore value of members from saved state
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
 } else {
    // Probably initialize members with default values for a new instance
 }

 }

Zamiast przywracać stan podczas onCreate() możesz zaimplementować onRestoreInstanceState(), który system wywoła po metodzie onStart(). System wywołuje onRestoreInstanceState() tylko wtedy, gdy istnieje zapisany stan do przywrócenia, więc nie musisz sprawdzać, czy Pakiet jest null:

  public void onRestoreInstanceState(Bundle savedInstanceState) {
  // Always call the superclass so it can restore the view hierarchy
  super.onRestoreInstanceState(savedInstanceState);

  // Restore state members from saved instance
  mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
  mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
 37
Author: Ravi Vaghela,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-28 08:16:39

onSaveInstanceState() dla danych przejściowych (przywracanych w onCreate()/onRestoreInstanceState()), onPause() dla danych trwałych (przywróconych w onResume()). Z zasobów technicznych Androida:

OnSaveInstanceState () jest wywoływana przez Androida, jeśli aktywność jest zatrzymana i może zostać zabita przed jej wznowieniem! Oznacza to, że po ponownym uruchomieniu działania powinien on przechowywać każdy stan niezbędny do ponownej inicjalizacji do tego samego stanu. Jest odpowiednikiem metody onCreate (), a w rzeczywistości pakietu savedInstanceState przekazywanie do OnCreate() jest Tym Samym pakietem, który konstruujesz jako outState w metodzie onSaveInstanceState ().

OnPause () i onResume () są również komplementarnymi metodami. onpause () jest zawsze wywoływane, gdy aktywność się kończy, nawet jeśli wywołaliśmy to (na przykład wywołaniem finish ()). Użyjemy tego, aby zapisać bieżącą notatkę z powrotem do bazy danych. Dobrą praktyką jest uwalnianie wszelkich zasobów, które mogą być uwalniane również podczas onPause (), aby zająć mniej zasoby w stanie pasywnym.

 35
Author: Ixx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-17 21:29:07

Naprawdę onSaveInstance Stan wywołania, gdy aktywność przechodzi w tło

Cytat z docs: "metoda onSaveInstanceState(Bundle) jest wywoływana przed umieszczeniem aktywności w takim stanie tła"

 31
Author: u-foka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-20 14:08:10

Tymczasem w ogóle nie używam

Bundle savedInstanceState & Co
Cykl na żywo jest dla większości czynności zbyt skomplikowany i niepotrzebny. A google twierdzi, że nie jest nawet wiarygodny.

Moim sposobem jest natychmiastowe zapisywanie zmian w preferencjach

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

W pewnym sensie Sharedpreferencje działają podobnie jak Pakiety. I naturalnie i na początku takie wartości muszą być czerwone od preferencji.

W przypadku złożonych danych możesz użyć Sqlite zamiast używać preferencje.

Podczas stosowania tej koncepcji działanie nadal używa ostatniego zapisanego stanu, niezależnie od tego, czy było to początkowe otwarcie z ponownym uruchomieniem pomiędzy, czy ponowne otwarcie z powodu tylnego stosu.

 27
Author: stefan bachert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-31 13:36:59

Aby zmniejszyć boilerplate używam następujących interface i class do odczytu/zapisu do Bundle w celu zapisania stanu instancji.


Najpierw Utwórz interfejs, który będzie używany do opisywania zmiennych instancji:

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 {

}

Następnie utwórz klasę, w której reflection będzie używane do zapisywania wartości w pakiecie:

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();
        }
    }

}

Przykładowe użycie:

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);
    }

}

Uwaga: ten kod został zaadaptowany z projektu biblioteki o nazwie AndroidAutowire, który jest licencjonowane na podstawie licencji MIT .

 26
Author: Jared Rummler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-20 02:04:11

Aby odpowiedzieć bezpośrednio na pierwotne pytanie. savedInstancestate jest null, ponieważ Twoja aktywność nigdy nie jest ponownie tworzona.

Twoja aktywność zostanie odtworzona z pakietem stanu tylko wtedy, gdy:

  • Zmiany konfiguracji, takie jak zmiana orientacji lub języka telefonu, które mogą wymagać utworzenia nowej instancji aktywności.
  • wracasz do aplikacji z tła po tym, jak system operacyjny zniszczył aktywność.

Android zniszczy tło czynności, gdy są pod presją pamięci lub gdy są w tle przez dłuższy czas.

Podczas testowania przykładu hello world istnieje kilka sposobów na opuszczenie i powrót do aktywności.

  • Po naciśnięciu przycisku Wstecz czynność jest zakończona. Ponowne uruchomienie aplikacji to zupełnie nowa instancja. W ogóle nie wracasz z tła.
  • po naciśnięciu przycisku home lub użyciu przełącznika zadań aktywność przejdzie w tło. Kiedy powrót do aplikacji onCreate zostanie wywołany tylko wtedy, gdy aktywność musiała zostać zniszczona.

W większości przypadków, jeśli po prostu naciskasz home, A następnie ponownie uruchamiasz aplikację, Aktywność nie będzie musiała być ponownie utworzona. Istnieje już w pamięci, więc OnCreate() nie zostanie wywołana.

Istnieje opcja w Ustawieniach - > opcje dewelopera o nazwie "nie zachowuj aktywności". Po włączeniu Android zawsze zniszczy działania i odtworzy je, gdy zostaną zablokowane. Jest to świetna opcja, aby pozostawić włączone podczas tworzenia, ponieważ symuluje najgorszy scenariusz. (Urządzenie o niskiej pamięci, które cały czas przetwarza Twoje działania ).

Inne odpowiedzi są cenne, ponieważ uczą cię poprawnych sposobów przechowywania stanu, ale nie czułem, że naprawdę odpowiedzieli, Dlaczego Twój kod nie działa tak, jak oczekiwałeś.

 24
Author: Jared Kells,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-21 02:19:16

Metody onSaveInstanceState(bundle) i onRestoreInstanceState(bundle) są przydatne dla trwałości danych tylko podczas obracania ekranu (zmiana orientacji).
Nie są one nawet dobre podczas przełączania między aplikacjami (ponieważ metoda onSaveInstanceState() jest wywoływana, ale onCreate(bundle) i onRestoreInstanceState(bundle) nie jest wywoływana ponownie.
Aby uzyskać większą trwałość, użyj wspólnych preferencji. przeczytaj ten artykuł

 22
Author: Mahorad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-18 04:04:07

Mój problem polegał na tym, że potrzebowałem wytrwałości tylko w czasie życia aplikacji (tj. pojedynczego wykonania obejmującego uruchamianie innych pod-działań w ramach tej samej aplikacji i obracanie urządzenia itp.). Próbowałem różnych kombinacji powyższych odpowiedzi, ale nie dostałem tego, czego chciałem we wszystkich sytuacjach. W końcu udało mi się uzyskać odniesienie do savedInstanceState podczas onCreate: {]}

mySavedInstanceState=savedInstanceState;

I użyj tego, aby uzyskać zawartość mojej zmiennej, gdy jej potrzebowałem, wzdłuż linie:

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

Używam onSaveInstanceState i onRestoreInstanceState jak sugerowano powyżej, ale myślę, że mogę również lub alternatywnie użyć mojej metody, aby zapisać zmienną, gdy się zmienia (np. za pomocą putBoolean)

 14
Author: torwalker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-16 17:11:47

Chociaż przyjęta odpowiedź jest prawidłowa, istnieje szybsza i łatwiejsza metoda zapisywania stanu aktywności na Androidzie za pomocą biblioteki o nazwie Icepick. Icepick jest procesorem adnotacji, który dba o cały kod boilerplate używany do zapisywania i przywracania stanu dla Ciebie.

Robienie czegoś takiego z 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);
  }
}

To to samo co robienie tego:

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");
  }
}

Icepick będzie działał z dowolnym obiektem, który zapisuje swój stan za pomocą Bundle.

 11
Author: Kevin Cronly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-26 03:07:39

Istnieją zasadniczo dwa sposoby wdrożenia tej zmiany.

  1. za pomocą onSaveInstanceState() i onRestoreInstanceState().
  2. w manifeście android:configChanges="orientation|screenSize".
Naprawdę nie polecam stosowania drugiej metody. Ponieważ w jednym z moich doświadczeń powodowało to, że połowa ekranu urządzenia była czarna podczas obracania się z pionowego do poziomego i odwrotnie.

Używając pierwszej metody, o której mowa powyżej, możemy zapisać dane w przypadku zmiany orientacji lub zmiany konfiguracji. Znam sposób, w jaki można przechowywać wszelkie typ danych wewnątrz obiektu savedInstance state.

przykład: rozważ przypadek, jeśli chcesz utrzymać obiekt Json. Utwórz klasę modelu za pomocą getterów i setterów .

class MyModel extends Serializable{
JSONObject obj;

setJsonObject(JsonObject obj)
{
this.obj=obj;
}

JSONObject getJsonObject()
return this.obj;
} 
}

teraz w swojej aktywności w onCreate i onSaveInstanceState metoda wykonaj następujące czynności. Będzie to wyglądało mniej więcej tak:

@override
onCreate(Bundle savedInstaceState){
MyModel data= (MyModel)savedInstaceState.getSerializable("yourkey")
JSONObject obj=data.getJsonObject();
//Here you have retained JSONObject and can use.
}


@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//Obj is some json object 
MyModel dataToSave= new MyModel();
dataToSave.setJsonObject(obj);
oustate.putSerializable("yourkey",dataToSave); 

}
 11
Author: Krishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-22 05:48:59

Podczas tworzenia aktywności wywoływana jest metoda onCreate ().

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

SavedInstanceState jest obiektem klasy Bundle, który po raz pierwszy ma wartość null, ale zawiera wartości po odtworzeniu. Aby zapisać stan aktywności, musisz nadpisać metodę onSaveInstanceState ().

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

Umieść swoje wartości w" outState " obiekt Bundle, taki jak outState.putString ("klucz", "Witamy z powrotem") i zapisać dzwoniąc super. Gdy aktywność zostanie zniszczona, jej stan zostanie zapisany w obiekcie Bundle i może być przywrócone po rekreacji w onCreate () lub onRestoreInstanceState (). Pakiet otrzymany w OnCreate() i onRestoreInstanceState () są takie same.

   @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");
            }
    }

Lub

  //restores activity's saved state
 @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
      String restoredMessage=savedInstanceState.getString("key");
    }
 10
Author: Mansuu....,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-23 10:29:47

Jest to jeden z najbardziej znanych i cenionych na świecie producentów i dystrybutorów w Europie, a zarazem jeden z najbardziej rozpoznawalnych producentów i dystrybutorów w Europie.]}

@VVK-częściowo się nie zgadzam. Niektóre sposoby wychodzenia z aplikacji nie uruchamiają się onSaveInstanceState (oSIS). Ogranicza to przydatność osi. Its warto wspierać, dla minimalnych zasobów systemu operacyjnego, ale jeśli aplikacja chce Przywróć użytkownikowi stan, w którym był, bez względu na to, jak aplikacja na po zakończeniu, konieczne jest użycie metody trwałego przechowywania. używam onCreate, aby sprawdzić pakiet, a jeśli go brakuje, sprawdź trwałe przechowywanie.To centralizuje proces podejmowania decyzji. Mogę odzyskiwanie po awarii, lub przycisk Wstecz exit lub niestandardowy element menu Exit, lub get back to screen user was on many days later. - ToolmakerSteve Sep 19 '15 at 10: 38

 8
Author: samis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-07 16:02:51

Kod Kotlina:

Zapisz:

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

A następnie w onCreate() lub onRestoreInstanceState()

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

Dodaj wartości domyślne, jeśli nie chcesz mieć opcji

 7
Author: Rafols,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 19:42:32

Nie jestem pewien, czy moje rozwiązanie jest źle widziane, czy nie, ale używam powiązanej usługi do utrzymywania stanu ViewModel. Niezależnie od tego, czy przechowujesz go w pamięci w usłudze, czy utrzymujesz i pobierasz z bazy danych SQLLite, zależy to od twoich wymagań. To właśnie robią usługi o dowolnym smaku, świadczą usługi takie jak utrzymywanie stanu aplikacji i abstrakcyjna wspólna logika biznesowa.

Ze względu na ograniczenia pamięci i przetwarzania nieodłącznie związane z urządzeniami mobilnymi traktuję widoki Androida w podobny sposób jak strona www. Strona nie zachowuje stanu, jest wyłącznie składnikiem warstwy prezentacji, którego jedynym celem jest przedstawienie stanu aplikacji i akceptacja danych wejściowych użytkownika. Najnowsze trendy w architekturze aplikacji internetowych wykorzystują wzorzec age old Model, View, Controller (MVC), gdzie strona jest widokiem, dane domeny to model, a kontroler siedzi za usługą internetową. Ten sam wzór można zastosować w Androidzie, gdy widok jest dobrze ... Widok, model jest Twoje dane domeny i Kontroler jest realizowany jako usługa związana Android. Gdy chcesz, aby Widok wszedł w interakcję z kontrolerem, połącz go przy starcie/wznowieniu i rozłącz przy zatrzymaniu / wstrzymaniu.

To podejście daje dodatkowy bonus egzekwowania zasady projektowania separacji troski w tym, że wszystkie z was aplikacji logiki biznesowej mogą być przeniesione do usługi, która zmniejsza zduplikowaną logikę w wielu widokach i pozwala widok do egzekwowania innej ważnej zasady projektowania, jednej odpowiedzialności.

 5
Author: ComeIn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-09 12:57:37

Proste szybkie rozwiązanie tego problemu polega na użyciu IcePick

Najpierw skonfiguruj bibliotekę w app/build.gradle

repositories {
  maven {url "https://clojars.org/repo/"}
}
dependencies {
  compile 'frankiesardo:icepick:3.2.0'
  provided 'frankiesardo:icepick-processor:3.2.0'
}

Teraz sprawdźmy poniższy przykład, jak zapisać stan w aktywności

public class ExampleActivity extends Activity {
  @State String username; // This will be automatically saved and restored

  @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);
  }
}
Działa dla działań, fragmentów lub dowolnego obiektu, który musi serializować swój stan na pakiecie (np.]}

Icepick może również wygenerować kod stanu instancji dla niestandardowych widoków:

class CustomView extends View {
  @State int selectedPosition; // This will be automatically saved and restored

  @Override public Parcelable onSaveInstanceState() {
    return Icepick.saveInstanceState(this, super.onSaveInstanceState());
  }

  @Override public void onRestoreInstanceState(Parcelable state) {
    super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state));
  }

  // You can put the calls to Icepick into a BaseCustomView and inherit from it
  // All Views extending this CustomView automatically have state saved/restored
}
 5
Author: THANN Phearum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-14 02:26:57

Aby uzyskać dane stanu aktywności zapisane w onCreate(), najpierw należy zapisać dane w savedInstanceState poprzez nadpisanie metody SaveInstanceState(Bundle savedInstanceState).

Po wywołaniu metody activity destroy SaveInstanceState(Bundle savedInstanceState) i tam zapisujesz dane, które chcesz zapisać. I otrzymujesz to samo w onCreate() po ponownym uruchomieniu aktywności.(savedInstanceState nie będzie null, ponieważ zapisałeś w nim niektóre dane przed zniszczeniem aktywności)

 5
Author: ascii_walker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-03 12:02:09

Teraz Android dostarcza ViewModels do zapisywania stanu, powinieneś spróbować użyć tego zamiast saveInstanceState.

 1
Author: M Abdul Sami,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-27 11:51:27

Dodawanie LiveData (komponentów architektury Androida) do projektu

Dodaj następującą zależność

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

LiveData przyjmuje obserwatora i powiadamia go o zmianach danych tylko wtedy, gdy jest w stanie rozpoczętym lub wznowionym. Zaletą LiveData jest to, że gdy Twoja aktywność przechodzi w stan inny niż rozpoczęty lub wznowiony nie wywoła metody onChanged na obserwator .

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);
        }
    });

}
 0
Author: Shomu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-11 06:53:04