2013-04-10 14 views
18

ich ein paar ähnliche Fragen zu onSaveInstanceState gesehen haben nicht für Fragment s genannt zu werden, aber in meinem Fall Fragment Arbeit in Ordnung, es ist die Haupt FragmentActivity, die Probleme haben wird.FragmentActivity onSaveInstanceState nicht immer genannt

Der entsprechende Code sieht ziemlich einfach:

public class MyFActivity extends FragmentActivity implements ActionBar.TabListener { 
    String[] allValues; // data to save 

    @Override 
    protected void onSaveInstanceState (Bundle outState) { 
     Log.d("putting it!", allValues.toString()); 
     outState.putStringArray("allValues", allValues); 
     super.onSaveInstanceState(outState); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     if (savedInstanceState != null) { 
      allValues = savedInstanceState.getStringArray("allValues"); 
      Log.d("getting it!", allValues.toString()); 
     } 
    } 
} 

Wenn die Aktivität pausieren (mit der Zurück-Taste) wird die onSaveInstanceState nie genannt wird, und folglich savedInstanceState ist immer null im onCreate Methode auf die App wieder aufnehmen . Ich habe versucht, das Hinzufügen eines Block wie folgt aus:

@Override 
public void onPause() { 
    super.onPause(); 
    onSaveInstanceState(new Bundle());  
} 

, die in https://stackoverflow.com/a/14195202/362657 vorgeschlagen wurde, aber während onSaveInstanceState dann aufgerufen wird, savedInstanceState bleibt null innerhalb onCreate Methode. Was vermisse ich?

+3

"Beim Pausieren der Aktivität (mit der Zurück-Schaltfläche)" wird normalerweise das Fragment zerstört, so dass 'savedInstanceState' verloren ist. Siehst du den richtigen 'saveInstanceState' in' onCreate() ', wenn du das Gerät drehst? – Sam

+0

Anstatt onCreate, sollten Sie vielleicht onResume() verwenden? Wenn die Aktivität nur pausiert ist, sollte onCreate() nicht erneut aufgerufen werden, onResume() sollte – Tom

+0

Hm, das erklärt es! Zerstört ist es. – SaltyNuts

Antwort

77

Das Problem hier ist, dass Sie missverstehen, wie onSaveInstanceState funktioniert. Es wurde entwickelt, um den Zustand der Activity/Fragment für den Fall zu speichern, dass das Betriebssystem es aus Speichergründen oder Konfigurationsänderungen zerstören muss. Dieser Zustand wird dann in onCreate zurückgegeben, wenn der Activity/Fragment zu/neu gestartet wird.

In einem Fragment sind alle ihre Lebenszyklusrückrufe direkt an ihre Eltern Activity gebunden. So wird onSaveInstanceState auf dem Fragment aufgerufen, wenn sein Elternteil ActivityonSaveInstanceState genannt hat.

Wenn die Aktivität pausiert (mit der Zurück-Taste) wird die onSaveInstanceState nie genannt wird, und folglich savedInstanceState ist immer null innerhalb der onCreate Methode auf die App wieder aufzunehmen.

Bei der Wiedergabe gedrückt wird, wird der Benutzer die Activity zerstört und damit seine Kinder Fragment s, so gibt es keinen Grund onSaveInstanceState zu nennen, da die Instanz zerstört wird. Wenn Sie die Activity erneut öffnen, handelt es sich um eine brandneue Instanz ohne gespeicherten Status. Daher lautet die Bundle in onCreatenull. Dies verhält sich genau wie vorgesehen. Versuchen Sie jedoch, das Gerät zu drehen oder die Home-Taste zu drücken, dann sehen Sie, dass die Activity und ihre Kinder Fragment s onSaveInstanceState aufgerufen haben und in onCreate zurückgegeben wurden, wenn sie zurückgegeben werden.

Der Hack Sie hinzugefügt, direkt onSaveInstanceState(new Bundle()); innerhalb von nennen, ist eine sehr schlechte Praxis, wie Sie sollten nie Anruf direkt die Lifecycle-Rückrufe. Dadurch können Sie Ihre App in unzulässige Zustände versetzen.

Wenn Sie wirklich wollen, dass Ihre Daten über eine Instanz Ihrer App hinaus bestehen, empfehle ich Ihnen, die Verwendung von SharedPreferences oder databases für erweiterte Daten zu prüfen. Sie können Ihre persistenten Daten dann in onPause() oder bei jeder Änderung speichern.

Hoffe, das hilft.

+0

Vielen Dank für die gründliche Erklärung. Ich hatte den falschen Eindruck, dass der Zurück-Button die Aktivität in den Hintergrund stellt und nicht zerstört. – SaltyNuts

+0

Sie sind sehr willkommen, es ist ein kniffliges Konzept, und ist nicht so gut dokumentiert, wie ich es gerne sehen würde. –

+0

@dymeh, das ist fantastisch, +1 für Sie Sir –

7

In einem Update auf die akzeptierte Antwort:

onSaveInstanceState des Ein Fragment bezeichnet werden kann, wenn Sie einen ViewPager mit einem FragmentStatePagerAdapter (statt FragmentPagerAdapter)

FragmentStatePagerAdapter

verwenden Diese Die Version des Pagers ist nützlicher, wenn es eine große Anzahl von Seiten gibt, die mehr wie eine Listenansicht funktionieren. Wenn Seiten für den Benutzer nicht sichtbar sind, kann ihr gesamtes Fragment zerstört werden, wobei nur der gespeicherte Zustand dieses Fragments beibehalten wird. Dadurch kann der Pager im Vergleich zu FragmentPagerAdapter viel weniger Speicher behalten, der mit jeder besuchten Seite verbunden ist, und zwar auf Kosten von möglicherweise mehr Aufwand beim Wechseln zwischen den Seiten.

Und nicht vergessen:

Wenn der Host ViewPager mit FragmentPagerAdapter muss eine gültige ID festgelegt hat.

+0

Du hast mein Leben gerettet: D –

Verwandte Themen