Vraag Android-status opslaan met de status Instance opslaan


Ik heb gewerkt aan het Android SDK-platform en het is een beetje onduidelijk hoe de status van een applicatie kan worden opgeslagen. Dus gezien deze kleine herschikking van het 'Hello, Android'-voorbeeld:

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

Ik dacht dat het genoeg zou zijn voor het eenvoudigste geval, maar het antwoordt altijd met het eerste bericht, ongeacht hoe ik weg navigeer van de app.

Ik ben er zeker van dat de oplossing even eenvoudig is als doorschakelen onPause of iets dergelijks, maar ik heb ongeveer 30 minuten in de documentatie rondgezworven en niets duidelijk gevonden.


2234
2017-09-30 04:41


oorsprong


antwoorden:


Je moet negeren onSaveInstanceState(Bundle savedInstanceState) en schrijf de waarden van de toepassingsstatus die u wilt wijzigen in de Bundle parameter als deze:

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

De bundel is in wezen een manier om een ​​NVP-kaart ("Name-Value Pair") op te slaan en deze wordt doorgegeven aan onCreate() en ook onRestoreInstanceState() waar je de waarden als volgt zou extraheren:

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

U zou deze techniek gewoonlijk gebruiken om instancewaarden voor uw toepassing op te slaan (selecties, niet-opgeslagen tekst, enz.).


2271
2017-09-30 06:12



De savedInstanceState is alleen voor het opslaan van de status die is gekoppeld aan een huidig ​​exemplaar van een activiteit, bijvoorbeeld de huidige navigatie- of selectiegegevens, zodat als Android een activiteit vernietigt en opnieuw creëert, deze terug kan komen zoals eerder. Zie de documentatie voor onCreate en onSaveInstanceState

Overweeg om een ​​langere levensduur te gebruiken een SQLite-database, een bestand of voorkeuren te gebruiken. Zien Persistente staat opslaan.


375
2017-09-30 05:03



Merk op dat dat zo is NIET veilig in gebruik onSaveInstanceState en onRestoreInstanceState  voor persistente gegevens, volgens de documentatie over de activiteitenstatus in http://developer.android.com/reference/android/app/Activity.html.

In het document wordt vermeld (in het gedeelte 'Activiteitslifecycle'):

Merk op dat het belangrijk is om op te slaan   persistente gegevens in onPause() in plaats daarvan   van onSaveInstanceState(Bundle)   omdat de laatste geen deel uitmaakt van de   levenscyclus callbacks, dus zal niet   belde elke situatie op zoals beschreven   in zijn documentatie.

Met andere woorden, zet uw bewaar- / herstelcode voor persistente gegevens in onPause() en onResume()!

BEWERK: Voor meer informatie, hier is de onSaveInstanceState() documentatie:

Deze methode wordt genoemd voordat een activiteit kan worden gedood, zodat wanneer dat gebeurt   komt terug in de toekomst in de toekomst kan het zijn staat herstellen. Voor   Bijvoorbeeld als activiteit B wordt gelanceerd voor activiteit A en voor sommigen   puntactiviteit A wordt gedood om middelen terug te vorderen, activiteit A zal hebben   een kans om via dit de huidige status van de gebruikersinterface op te slaan   methode zodat wanneer de gebruiker terugkeert naar activiteit A, de staat van de   gebruikersinterface kan worden hersteld via onCreate(Bundle) of    onRestoreInstanceState(Bundle).


365
2018-05-25 23:22



Mijn collega schreef een artikel over de toepassingsstatus op Android-apparaten, inclusief uitleg over de activiteitenlevenscyclus en staatsinformatie, hoe informatie over de staat op te slaan en te sparen naar de staat Bundle en SharedPreferences en kijk hier eens.

Het artikel behandelt drie benaderingen:

Sla lokale varible / UI-besturingsgegevens op voor de levensduur van de toepassing (dwz tijdelijk) met behulp van Instance State Bundle

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

Bewaar lokale varible / UI-besturingsgegevens tussen applicatie-exemplaren (dwz permanent) met behulp van Gedeelde voorkeuren

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

Objecten van objecten levend houden in het geheugen tussen activiteiten binnen de levensduur van de toepassing met behoud van de niet-geconfigureerde instantie

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

171
2017-08-27 13:54



Dit is een klassieke 'gotcha' van Android-ontwikkeling. Er zijn twee problemen hier:

  • Er is een subtiele Android Framework-bug die het beheer van applicatie stacks aanzienlijk bemoeilijkt tijdens de ontwikkeling, tenminste op oudere versies (niet helemaal zeker of / wanneer / hoe het was opgelost). Ik zal deze bug hieronder bespreken.
  • De 'normale' of de bedoelde manier om dit probleem te beheren is op zichzelf nogal ingewikkeld met de dualiteit van onPause / onResume en onSaveInstanceState / onRestoreInstanceState

Als ik door al deze discussies blader, vermoed ik dat veel van de ontwikkelaars het hebben over deze twee verschillende problemen tegelijkertijd ... vandaar alle verwarring en verslagen van "dit werkt niet voor mij".

Allereerst om het 'bedoelde' gedrag te verduidelijken: onSaveInstance en onRestoreInstance zijn fragiel en alleen voor de overgangstoestand. Het beoogde gebruik (afaict) is om activiteiten te recreëren wanneer de telefoon geroteerd is (verandering van richting). Met andere woorden, het bedoelde gebruik is wanneer uw activiteit nog steeds logisch 'bovenaan' staat, maar nog steeds door het systeem moet worden hersteld. De opgeslagen bundel blijft niet bestaan ​​buiten het proces / geheugen / gc, dus u kunt hier niet echt op vertrouwen als uw activiteit naar de achtergrond gaat. Ja, misschien zal het geheugen van je activiteit de reis naar de achtergrond overleven en GC ontsnappen, maar dit is niet betrouwbaar (het is ook niet voorspelbaar).

Dus als u een scenario hebt met een betekenisvolle 'voortgang van de gebruiker' of een status die moet blijven bestaan ​​tussen de 'lanceringen' van uw toepassing, is de leidraad om onPause en onResume te gebruiken. U moet zelf een permanente winkel kiezen en voorbereiden.

MAAR - er is een zeer verwarrende bug die dit allemaal compliceert. Details zijn hier:

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

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

Kort gezegd: als uw toepassing wordt gestart met de vlag SingleTask en later start u deze vanuit het startscherm of het startmenu, dan maakt die volgende aanroep een NIEUWE taak ... u zult effectief twee verschillende exemplaren van uw app hebben in dezelfde stapel wonen ... die erg razend snel wordt. Dit lijkt te gebeuren wanneer u uw app tijdens de ontwikkeling start (bijv. Van Eclipse of Intellij), dus ontwikkelaars komen hier vaak tegenaan. Maar ook via een aantal van de updates voor de update van de app store (dus het heeft ook invloed op uw gebruikers).

Ik heb uren door deze threads gevochten voordat ik me realiseerde dat mijn grootste probleem deze bug was, niet het bedoelde kadergedrag. Een geweldige beschrijving en tijdelijke oplossing (UPDATE: zie hieronder) lijkt van gebruiker @kaciula te zijn in dit antwoord:

Startsleutelpersgedrag

UPDATE juni 2013: Maanden later heb ik eindelijk de 'juiste' oplossing gevonden. U hoeft zelf geen stateful startedApp-vlaggen te beheren, u kunt dit op basis van het framework detecteren en op de juiste manier op borgtocht vrijgeven. Ik gebruik dit aan het begin van mijn 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;
    }
}

126
2017-10-19 23:47



onSaveInstanceStatewordt aangeroepen wanneer het systeem geheugen nodig heeft en een toepassing doodt. Het wordt niet opgeroepen wanneer de gebruiker de applicatie gewoon sluit. Dus ik denk dat de applicatiestatus ook moet worden opgeslagen onPause Het zou moeten worden opgeslagen in een aantal permanente opslag zoals Preferences of Sqlite


70
2018-05-07 00:21



Beide methoden zijn nuttig en geldig en beide zijn het meest geschikt voor verschillende scenario's:

  1. De gebruiker beëindigt de toepassing en opent deze op een later tijdstip opnieuw, maar de toepassing moet gegevens van de laatste sessie opnieuw laden - dit vereist een permanente opslagaanpak, zoals het gebruik van SQLite.
  2. De gebruiker wisselt van applicatie en komt dan terug naar het origineel en wil verdergaan waar hij was gebleven - bundelgegevens (zoals applicatiestatusgegevens) opslaan en herstellen in onSaveInstanceState() en onRestoreInstanceState() is meestal voldoende.

Als u de statusgegevens op een persistente manier opslaat, kan deze opnieuw worden geladen in een onResume() of onCreate() (of eigenlijk tijdens elke lifecycle-aanroep). Dit kan al dan niet gewenst gedrag zijn. Als u het opslaat in een bundel in een InstanceState, dan is het van voorbijgaande aard en is het alleen geschikt voor het opslaan van gegevens voor gebruik in dezelfde gebruikerssessie (ik gebruik de term sessie losjes) maar niet tussen 'sessies'.

Het is niet dat de ene aanpak beter is dan de andere, zoals alles, het is alleen belangrijk om te begrijpen welk gedrag je nodig hebt en om de meest geschikte aanpak te kiezen.


59
2018-06-27 16:17