Aktivitätslebenszyklus
Aktivitäten sind ein grundlegender Baustein von Android-Anwendungen und können in einer Reihe verschiedener Zustände vorhanden sein. Der Aktivitätslebenszyklus beginnt mit der Instanziierung und endet mit der Zerstörung und umfasst viele Zustände dazwischen. Wenn eine Aktivität den Zustand ändert, wird die entsprechende Lebenszyklusereignismethode aufgerufen, die die Aktivität über die bevorstehende Zustandsänderung benachrichtigt und ihr ermöglicht, Code auszuführen, um sich an diese Änderung anzupassen. In diesem Artikel wird der Lebenszyklus von Aktivitäten untersucht und die Verantwortung erläutert, die eine Aktivität während jeder dieser Zustandsänderungen hat, um Teil einer ordnungsgemäßen, zuverlässigen Anwendung zu sein.
Übersicht über den Aktivitätslebenszyklus
Aktivitäten sind ein ungewöhnliches Programmierkonzept speziell für Android. In der herkömmlichen Anwendungsentwicklung gibt es in der Regel eine statische Standard-Methode, die zum Starten der Anwendung ausgeführt wird. Bei Android sind die Dinge jedoch anders; Android-Anwendungen können über jede registrierte Aktivität innerhalb einer Anwendung gestartet werden. In der Praxis verfügen die meisten Anwendungen nur über eine bestimmte Aktivität, die als Anwendungseinstiegspunkt angegeben wird. Wenn eine Anwendung jedoch abstürzt oder vom Betriebssystem beendet wird, kann das Betriebssystem versuchen, die Anwendung bei der letzten geöffneten Aktivität oder an einer anderen Stelle innerhalb des vorherigen Aktivitätsstapels neu zu starten. Darüber hinaus kann das Betriebssystem Aktivitäten anhalten, wenn sie nicht aktiv sind, und sie zurückgibt, wenn es nicht genügend Arbeitsspeicher hat. Es muss sorgfältig überlegt werden, damit die Anwendung ihren Zustand ordnungsgemäß wiederherstellen kann, wenn eine Aktivität neu gestartet wird, insbesondere wenn diese Aktivität von Daten aus vorherigen Aktivitäten abhängt.
Der Aktivitätslebenszyklus wird als Sammlung von Methoden implementiert, die das Betriebssystem während des gesamten Lebenszyklus einer Aktivität aufruft. Mit diesen Methoden können Entwickler die Funktionalität implementieren, die erforderlich ist, um die Anforderungen an die Zustands- und Ressourcenverwaltung ihrer Anwendungen zu erfüllen.
Es ist äußerst wichtig, dass der Anwendungsentwickler die Anforderungen jeder Aktivität analysiert, um zu bestimmen, welche Methoden, die durch den Aktivitätslebenszyklus verfügbar gemacht werden, implementiert werden müssen. Andernfalls kann dies zu Anwendungsinstabilität, Abstürze, Ressourcenblähungen und möglicherweise sogar zu zugrunde liegender Betriebssysteminstabilität führen.
In diesem Kapitel wird der Aktivitätslebenszyklus ausführlich untersucht, einschließlich:
- Aktivitätsstatus
- Lebenszyklusmethoden
- Beibehalten des Status einer Anwendung
Dieser Abschnitt enthält auch eine exemplarische Vorgehensweise , die praktische Beispiele zum effizienten Speichern des Zustands während des Aktivitätslebenszyklus enthält. Am Ende dieses Kapitels sollten Sie den Aktivitätslebenszyklus und dessen Unterstützung in einer Android-Anwendung verstehen.
Aktivitätslebenszyklus
Der Android-Aktivitätslebenszyklus umfasst eine Sammlung von Methoden, die innerhalb der Activity-Klasse verfügbar gemacht werden und dem Entwickler ein Ressourcenverwaltungsframework bereitstellen. Dieses Framework ermöglicht es Entwicklern, die individuellen Zustandsverwaltungsanforderungen jeder Aktivität innerhalb einer Anwendung zu erfüllen und die Ressourcenverwaltung ordnungsgemäß zu verarbeiten.
Aktivitätsstatus
Das Android-Betriebssystem vermittelt Aktivitäten basierend auf ihrem Zustand. Dies hilft Android dabei, Aktivitäten zu identifizieren, die nicht mehr verwendet werden, sodass das Betriebssystem Arbeitsspeicher und Ressourcen zurückgewinnen kann. Das folgende Diagramm veranschaulicht die Zustände, die eine Aktivität während ihrer Lebensdauer durchlaufen kann:
Diese Zustände können wie folgt in vier Standard Gruppen unterteilt werden:
Aktiv oder Ausgeführt : Aktivitäten werden als aktiv oder ausgeführt betrachtet, wenn sie sich im Vordergrund befinden, auch als oberster Bereich des Aktivitätsstapels bezeichnet. Dies gilt als Aktivität mit der höchsten Priorität in Android und wird daher nur in Extremsituationen vom Betriebssystem beendet, z. B. wenn die Aktivität versucht, mehr Arbeitsspeicher zu verwenden, als auf dem Gerät verfügbar ist, da dies dazu führen könnte, dass die Benutzeroberfläche nicht mehr reagiert.
Angehalten : Wenn das Gerät in den Standbymodus wechselt oder eine Aktivität noch sichtbar, aber teilweise durch eine neue, nicht vollständige oder transparente Aktivität ausgeblendet ist, wird die Aktivität als angehalten betrachtet. Angehaltene Aktivitäten sind noch aktiv, d. h., sie behalten alle Status- und Mitgliedsinformationen bei und bleiben an den Fenster-Manager angefügt. Dies gilt als aktivität mit der zweithöchsten Priorität in Android und wird daher vom Betriebssystem nur beendet, wenn das Beenden dieser Aktivität die Ressourcenanforderungen erfüllt, die erforderlich sind, um die Aktive/Laufende Aktivität stabil und reaktionsfähig zu halten.
Beendet/Hintergrund: Aktivitäten, die von einer anderen Aktivität vollständig verdeckt werden, werden als beendet oder im Hintergrund betrachtet. Beendete Aktivitäten versuchen weiterhin, ihre Status- und Mitgliedsinformationen so lange wie möglich beizubehalten, aber beendete Aktivitäten werden als die niedrigste Priorität der drei Zustände angesehen, und daher beendet das Betriebssystem zuerst Aktivitäten in diesem Zustand, um die Ressourcenanforderungen von Aktivitäten mit höherer Priorität zu erfüllen.
Neustarten : Es ist möglich, dass eine Aktivität, die im Lebenszyklus angehalten bis angehalten ist, von Android aus dem Arbeitsspeicher entfernt wird. Wenn der Benutzer zurück zur Aktivität navigiert, muss sie neu gestartet, in den zuvor gespeicherten Zustand wiederhergestellt und dann für den Benutzer angezeigt werden.
Aktivität Re-Creation als Reaktion auf Konfigurationsänderungen
Um die Sache komplizierter zu machen, löst Android einen weiteren Schraubenschlüssel in der Mischung namens Konfigurationsänderungen aus. Konfigurationsänderungen sind schnelle Aktivitätszerstörungs-/Neuerstellungszyklen, die auftreten, wenn sich die Konfiguration einer Aktivität ändert, z. B. wenn das Gerät gedreht wird (und die Aktivität im Quer- oder Hochformatmodus neu erstellt werden muss), wenn die Tastatur angezeigt wird (und die Aktivität die Möglichkeit hat, sich selbst zu ändern) oder wenn das Gerät in einem Dock platziert wird. unter anderem.
Konfigurationsänderungen verursachen weiterhin die gleichen Aktivitätsstatusänderungen, die beim Beenden und Neustarten einer Aktivität auftreten würden. Um jedoch sicherzustellen, dass sich eine Anwendung reaktionsfähig fühlt und bei Konfigurationsänderungen gut funktioniert, ist es wichtig, dass sie so schnell wie möglich verarbeitet werden. Daher verfügt Android über eine bestimmte API, die verwendet werden kann, um den Zustand bei Konfigurationsänderungen beizubehalten. Dies wird später im Abschnitt Verwalten des Zustands im gesamten Lebenszyklus behandelt.
Aktivitätslebenszyklus-Methoden
Das Android SDK und das Xamarin.Android-Framework bieten ein leistungsfähiges Modell zum Verwalten des Status von Aktivitäten in einer Anwendung. Wenn sich der Status einer Aktivität ändert, wird die Aktivität vom Betriebssystem benachrichtigt, das bestimmte Methoden für diese Aktivität aufruft. Das folgende Diagramm veranschaulicht diese Methoden in Bezug auf den Aktivitätslebenszyklus:
Als Entwickler können Sie Zustandsänderungen verarbeiten, indem Sie diese Methoden innerhalb einer Aktivität überschreiben. Es ist jedoch wichtig zu beachten, dass alle Lebenszyklusmethoden im UI-Thread aufgerufen werden und das Betriebssystem daran hindert, die nächste Arbeit der Benutzeroberfläche auszuführen, z. B. das Ausblenden der aktuellen Aktivität, das Anzeigen einer neuen Aktivität usw. Daher sollte der Code in diesen Methoden so kurz wie möglich sein, damit sich eine Anwendung gut funktioniert. Alle Aufgaben mit langer Ausführungsdauer sollten in einem Hintergrundthread ausgeführt werden.
Sehen wir uns die einzelnen Lebenszyklusmethoden und deren Verwendung an:
OnCreate
OnCreate ist die erste Methode, die aufgerufen wird, wenn eine Aktivität erstellt wird.
OnCreate
wird immer überschrieben, um alle Startinitialisierungen auszuführen, die für eine Aktivität erforderlich sein können, z. B.:
- Erstellen von Ansichten
- Initialisieren von Variablen
- Binden statischer Daten an Listen
OnCreate
nimmt einen Bundle-Parameter an. Dabei handelt es sich um ein Wörterbuch zum Speichern und Übergeben von Zustandsinformationen und Objekten zwischen Aktivitäten. Wenn das Bundle nicht NULL ist, gibt dies an, dass die Aktivität neu gestartet wird und ihr Zustand aus dem vorherigen instance wiederhergestellt werden soll. Der folgende Code veranschaulicht, wie Werte aus dem Bundle abgerufen werden:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
string intentString;
bool intentBool;
if (bundle != null)
{
intentString = bundle.GetString("myString");
intentBool = bundle.GetBoolean("myBool");
}
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
}
Sobald OnCreate
der Vorgang abgeschlossen ist, ruft Android auf OnStart
.
OnStart
OnStart wird immer vom System aufgerufen, nachdem OnCreate
der Vorgang abgeschlossen ist. Aktivitäten können diese Methode außer Kraft setzen, wenn sie bestimmte Aufgaben ausführen müssen, bevor eine Aktivität sichtbar wird, z. B. das Aktualisieren aktueller Werte von Ansichten innerhalb der Aktivität. Android ruft unmittelbar nach dieser Methode auf OnResume
.
OnResume
Das System ruft OnResume auf, wenn die Aktivität bereit ist, mit der Interaktion mit dem Benutzer zu beginnen. Aktivitäten sollten diese Methode überschreiben, um Aufgaben wie die folgenden auszuführen:
- Hochfahren von Bildfrequenzen (eine häufige Aufgabe bei der Spieleentwicklung)
- Starten von Animationen
- Lauschen auf GPS-Updates
- Anzeigen relevanter Warnungen oder Dialogfelder
- Verknüpfen externer Ereignishandler
Der folgende Codeausschnitt zeigt beispielsweise, wie die Kamera initialisiert wird:
protected override void OnResume()
{
base.OnResume(); // Always call the superclass first.
if (_camera==null)
{
// Do camera initializations here
}
}
OnResume
ist wichtig, da jeder Vorgang, der in OnPause
ausgeführt wird, in OnResume
nicht ausgeführt werden sollte, da es sich um die einzige Lebenszyklusmethode handelt, die garantiert nach OnPause
ausgeführt wird, wenn die Aktivität wieder zum Leben erweckt wird.
Onpause
OnPause wird aufgerufen, wenn das System dabei ist, die Aktivität in den Hintergrund zu setzen oder wenn die Aktivität teilweise verdeckt wird. Aktivitäten sollten diese Methode außer Kraft setzen, wenn folgendes erforderlich ist:
Committen von nicht gespeicherten Änderungen an persistenten Daten
Zerstören oder sauber andere Objekte, die Ressourcen verbrauchen
Herunterfahren von Bildfrequenzen und Anhalten von Animationen
Heben Sie die Registrierung externer Ereignishandler oder Benachrichtigungshandler auf (d. h. solche, die an einen Dienst gebunden sind). Dies muss geschehen, um Speicherverluste der Aktivität zu verhindern.
Wenn die Aktivität Dialogfelder oder Warnungen angezeigt hat, müssen diese mit der
.Dismiss()
-Methode bereinigt werden.
Der folgende Codeausschnitt gibt beispielsweise die Kamera frei, da die Aktivität sie während des Anhaltens nicht nutzen kann:
protected override void OnPause()
{
base.OnPause(); // Always call the superclass first
// Release the camera as other activities might need it
if (_camera != null)
{
_camera.Release();
_camera = null;
}
}
Es gibt zwei mögliche Lebenszyklusmethoden, die nach OnPause
aufgerufen werden:
-
OnResume
wird aufgerufen, wenn die Aktivität in den Vordergrund zurückgegeben werden soll. -
OnStop
wird aufgerufen, wenn die Aktivität im Hintergrund platziert wird.
OnStop
OnStop wird aufgerufen, wenn die Aktivität für den Benutzer nicht mehr sichtbar ist. Dies geschieht, wenn einer der folgenden Auftritte auftritt:
- Eine neue Aktivität wird gestartet und verschleiert diese Aktivität.
- Eine vorhandene Aktivität wird in den Vordergrund gestellt.
- Die Aktivität wird zerstört.
OnStop
kann in Situationen mit wenig Arbeitsspeicher nicht immer aufgerufen werden, z. B. wenn Android nach Ressourcen ausgehungert ist und die Aktivität nicht ordnungsgemäß hintergrunden kann. Aus diesem Grund ist es am besten, sich beim Vorbereiten einer Aktivität auf die Zerstörung nicht darauf OnStop
zu verlassen, aufgerufen zu werden. Die nächsten Lebenszyklusmethoden, die nach dieser aufgerufen werden können, sind OnDestroy
, wenn die Aktivität abläuft oder OnRestart
wenn die Aktivität zurückkommt, um mit dem Benutzer zu interagieren.
OnDestroy
OnDestroy ist die letzte Methode, die für eine Aktivität aufgerufen wird, instance bevor sie zerstört und vollständig aus dem Arbeitsspeicher entfernt wird. In extremen Situationen kann Android den Anwendungsprozess beenden, der die Aktivität hostt, was dazu führt OnDestroy
, dass nicht aufgerufen wird. Die meisten Aktivitäten implementieren diese Methode nicht, da die meisten sauber In- und Herunterfahren in den OnPause
Methoden und OnStop
durchgeführt wurden. Die OnDestroy
Methode wird in der Regel überschrieben, um aufgaben mit langer Ausführungsdauer zu sauber, die ressourcenlecken können. Ein Beispiel hierfür könnten Hintergrundthreads sein, die in OnCreate
gestartet wurden.
Es werden keine Lebenszyklusmethoden aufgerufen, nachdem die Aktivität zerstört wurde.
OnRestart
OnRestart wird aufgerufen, nachdem Ihre Aktivität beendet wurde, bevor sie erneut gestartet wird. Ein gutes Beispiel hierfür wäre, wenn der Benutzer die Startschaltfläche während einer Aktivität in der Anwendung drückt. Wenn dies geschieht OnPause
, OnStop
werden Methoden aufgerufen, und die Aktivität wird in den Hintergrund verschoben, aber nicht zerstört. Wenn der Benutzer dann die Anwendung mithilfe des Task-Managers oder einer ähnlichen Anwendung wiederherstellen sollte, ruft Android die OnRestart
Methode der Aktivität auf.
Es gibt keine allgemeinen Richtlinien für die Art von Logik, die in OnRestart
implementiert werden sollte. Dies liegt daran, dass OnStart
immer aufgerufen wird, unabhängig davon, ob die Aktivität erstellt oder neu gestartet wird. Daher sollten alle ressourcen, die für die Aktivität erforderlich sind, in OnStart
OnRestart
initialisiert werden.
Die nächste Lebenszyklusmethode, die nach OnRestart
aufgerufen wird, ist OnStart
.
Back vs. Home
Viele Android-Geräte verfügen über zwei unterschiedliche Schaltflächen: die Schaltfläche "Zurück" und die Schaltfläche "Start". Ein Beispiel hierfür finden Sie im folgenden Screenshot von Android 4.0.3:
Es gibt einen subtilen Unterschied zwischen den beiden Schaltflächen, auch wenn sie den gleichen Effekt haben, eine Anwendung im Hintergrund zu platzieren. Wenn ein Benutzer auf die Schaltfläche Zurück klickt, teilt er Android mit, dass er mit der Aktivität fertig ist. Android zerstört die Aktivität. Wenn der Benutzer hingegen auf die Schaltfläche Start klickt, wird die Aktivität nur im Hintergrund platziert – Android beendet die Aktivität nicht.
Verwalten des Zustands während des gesamten Lebenszyklus
Wenn eine Aktivität beendet oder zerstört wird, bietet das System die Möglichkeit, den Status der Aktivität für eine spätere Rehydrierung zu speichern. Dieser gespeicherte Zustand wird als instance Zustand bezeichnet. Android bietet drei Optionen zum Speichern instance Zustands während des Aktivitätslebenszyklus:
Speichern von primitiven Werten in einem
Dictionary
sogenannten Bundle , das Android zum Speichern des Zustands verwendet.Erstellen einer benutzerdefinierten Klasse, die komplexe Werte wie Bitmaps enthält. Android verwendet diese benutzerdefinierte Klasse zum Speichern des Zustands.
Umgehung des Konfigurationsänderungslebenszyklus und Übernahme der vollständigen Verantwortung für die Aufrechterhaltung des Zustands in der Aktivität.
In diesem Leitfaden werden die ersten beiden Optionen behandelt.
Bündelstatus
Die primäre Option zum Speichern instance Zustands besteht darin, ein Schlüssel-Wert-Wörterbuchobjekt zu verwenden, das als Bundle bezeichnet wird.
Wenn eine Aktivität erstellt wird, dass die OnCreate
Methode ein Bundle als Parameter übergeben wird, kann dieses Bündel verwendet werden, um den instance Zustand wiederherzustellen. Es wird nicht empfohlen, ein Bündel für komplexere Daten zu verwenden, die nicht schnell oder einfach in Schlüssel-Wert-Paare serialisiert werden (z. B. Bitmaps). sie sollte vielmehr für einfache Werte wie Zeichenfolgen verwendet werden.
Eine Aktivität bietet Methoden zum Speichern und Abrufen des instance Zustands im Bundle:
OnSaveInstanceState : Dies wird von Android aufgerufen, wenn die Aktivität zerstört wird. Aktivitäten können diese Methode implementieren, wenn sie Schlüssel-Wert-Zustandselemente beibehalten müssen.
OnRestoreInstanceState : Dies wird aufgerufen, nachdem die
OnCreate
-Methode abgeschlossen ist, und bietet eine weitere Möglichkeit für eine Aktivität, ihren Zustand wiederherzustellen, nachdem die Initialisierung abgeschlossen ist.
Das folgende Diagramm veranschaulicht, wie diese Methoden verwendet werden:
OnSaveInstanceState
OnSaveInstanceState wird aufgerufen, wenn die Aktivität beendet wird. Sie erhält einen Bündelparameter, in dem die Aktivität ihren Status speichern kann. Wenn ein Gerät eine Konfigurationsänderung erlebt, kann eine Aktivität das Bundle
übergebene Objekt verwenden, um den Aktivitätsstatus beizubehalten, indem sie überschreibt OnSaveInstanceState
. Beachten Sie z. B. folgenden Code:
int c;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
this.SetContentView (Resource.Layout.SimpleStateView);
var output = this.FindViewById<TextView> (Resource.Id.outputText);
if (bundle != null) {
c = bundle.GetInt ("counter", -1);
} else {
c = -1;
}
output.Text = c.ToString ();
var incrementCounter = this.FindViewById<Button> (Resource.Id.incrementCounter);
incrementCounter.Click += (s,e) => {
output.Text = (++c).ToString();
};
}
Der obige Code erhöht eine ganze Zahl mit dem Namen c
, wenn auf eine Schaltfläche mit dem Namen incrementCounter
geklickt wird, und zeigt das Ergebnis in einem TextView
namens output
an. Wenn eine Konfigurationsänderung erfolgt - z. B. wenn das Gerät gedreht wird -, verliert der obige Code den Wert von c
, da der bundle
sein würde null
, wie in der folgenden Abbildung dargestellt:
Um den Wert von c
in diesem Beispiel beizubehalten, kann die Aktivität den Wert im Bundle wie unten gezeigt überschreiben OnSaveInstanceState
:
protected override void OnSaveInstanceState (Bundle outState)
{
outState.PutInt ("counter", c);
base.OnSaveInstanceState (outState);
}
Wenn das Gerät nun in eine neue Ausrichtung gedreht wird, wird die ganze Zahl im Bundle gespeichert und mit der Zeile abgerufen:
c = bundle.GetInt ("counter", -1);
Hinweis
Es ist wichtig, immer die Basisimplementierung von OnSaveInstanceState
aufzurufen, damit auch der Zustand der Ansichtshierarchie gespeichert werden kann.
Ansichtsstatus
Das Überschreiben OnSaveInstanceState
ist ein geeigneter Mechanismus zum Speichern vorübergehender Daten in einer Aktivität über Ausrichtungsänderungen hinweg, wie z. B. der Zähler im obigen Beispiel. Die Standardimplementierung von OnSaveInstanceState
kümmert sich jedoch um das Speichern vorübergehender Daten in der Benutzeroberfläche für jede Ansicht, solange jeder Ansicht eine ID zugewiesen ist. Angenommen, eine Anwendung verfügt über ein EditText
Element, das in XML wie folgt definiert ist:
<EditText android:id="@+id/myText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
Da dem EditText
Steuerelement eine id
zugewiesen ist, werden die Daten weiterhin angezeigt, wenn der Benutzer einige Daten eingibt und das Gerät rotiert, wie unten gezeigt:
OnRestoreInstanceState
OnRestoreInstanceState wird nach OnStart
aufgerufen. Es bietet einer Aktivität die Möglichkeit, jeden Zustand wiederherzustellen, der zuvor während des vorherigen OnSaveInstanceState
gespeichert wurde. Dies ist jedoch das gleiche Bündel, das für OnCreate
bereitgestellt wird.
Der folgende Code veranschaulicht, wie der Zustand in OnRestoreInstanceState
wiederhergestellt werden kann:
protected override void OnRestoreInstanceState(Bundle savedState)
{
base.OnRestoreInstanceState(savedState);
var myString = savedState.GetString("myString");
var myBool = savedState.GetBoolean("myBool");
}
Diese Methode bietet eine gewisse Flexibilität bei der Wiederherstellung des Zustands. Manchmal ist es sinnvoller, zu warten, bis alle Initialisierungen abgeschlossen sind, bevor sie instance Zustand wiederherstellen. Darüber hinaus kann eine Unterklasse einer vorhandenen Aktivität nur bestimmte Werte aus dem instance Zustand wiederherstellen. In vielen Fällen ist es nicht erforderlich, den Zustand zu überschreiben OnRestoreInstanceState
, da die meisten Aktivitäten den Zustand mithilfe des für OnCreate
bereitgestellten Bundles wiederherstellen können.
Ein Beispiel für das Speichern des Zustands mithilfe eines Bundle
finden Sie unter Exemplarische Vorgehensweise : Speichern des Aktivitätszustands.
Bundleeinschränkungen
Obwohl OnSaveInstanceState
das Speichern vorübergehender Daten einfach ist, gibt es einige Einschränkungen:
Es wird nicht in allen Fällen aufgerufen. Wenn Sie z. B. start oder zurück drücken, um eine Aktivität zu beenden, wird
OnSaveInstanceState
nicht aufgerufen.Das übergebene
OnSaveInstanceState
Bundle ist nicht für große Objekte, z. B. Bilder, konzipiert. Bei großen Objekten ist das Speichern des Objekts aus OnRetainNonConfigurationInstance vorzuziehen, wie unten erläutert.Mithilfe des Bundles gespeicherte Daten werden serialisiert, was zu Verzögerungen führen kann.
Der Bündelzustand ist nützlich für einfache Daten, die nicht viel Arbeitsspeicher beanspruchen, während nicht konfigurierte instance Daten für komplexere Daten oder für Daten, die teuer abgerufen werden können, z. B. aus einem Webdienstaufruf oder einer komplizierten Datenbankabfrage, nützlich sind. Nicht konfigurierte instance Daten werden nach Bedarf in einem Objekt gespeichert. Im nächsten Abschnitt wird vorgestellt, wie komplexere Datentypen OnRetainNonConfigurationInstance
durch Konfigurationsänderungen beibehalten werden können.
Beibehalten komplexer Daten
Zusätzlich zum Beibehalten von Daten im Bundle unterstützt Android auch das Speichern von Daten, indem OnRetainNonConfigurationInstance überschrieben und eine instance einer Java.Lang.Object
zurückgegeben wird, die die zu speichernden Daten enthält. Es gibt zwei Hauptvorteile der Verwendung OnRetainNonConfigurationInstance
zum Speichern des Zustands:
Das von
OnRetainNonConfigurationInstance
zurückgegebene Objekt funktioniert gut mit größeren, komplexeren Datentypen, da dieses Objekt im Arbeitsspeicher beibehalten wird.Die
OnRetainNonConfigurationInstance
Methode wird bei Bedarf und nur bei Bedarf aufgerufen. Dies ist kostengünstiger als die Verwendung eines manuellen Caches.
Die Verwendung OnRetainNonConfigurationInstance
eignet sich für Szenarien, in denen es teuer ist, die Daten mehrmals abzurufen, z. B. in Webdienstaufrufen. Betrachten Sie beispielsweise den folgenden Code, der Twitter durchsucht:
public class NonConfigInstanceActivity : ListActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SearchTwitter ("xamarin");
}
public void SearchTwitter (string text)
{
string searchUrl = String.Format("http://search.twitter.com/search.json?" + "q={0}&rpp=10&include_entities=false&" + "result_type=mixed", text);
var httpReq = (HttpWebRequest)HttpWebRequest.Create (new Uri (searchUrl));
httpReq.BeginGetResponse (new AsyncCallback (ResponseCallback), httpReq);
}
void ResponseCallback (IAsyncResult ar)
{
var httpReq = (HttpWebRequest)ar.AsyncState;
using (var httpRes = (HttpWebResponse)httpReq.EndGetResponse (ar)) {
ParseResults (httpRes);
}
}
void ParseResults (HttpWebResponse httpRes)
{
var s = httpRes.GetResponseStream ();
var j = (JsonObject)JsonObject.Load (s);
var results = (from result in (JsonArray)j ["results"] let jResult = result as JsonObject select jResult ["text"].ToString ()).ToArray ();
RunOnUiThread (() => {
PopulateTweetList (results);
});
}
void PopulateTweetList (string[] results)
{
ListAdapter = new ArrayAdapter<string> (this, Resource.Layout.ItemView, results);
}
}
Dieser Code ruft Ergebnisse aus dem als JSON formatierten Web ab, analysiert sie und zeigt die Ergebnisse dann in einer Liste an, wie im folgenden Screenshot gezeigt:
Wenn eine Konfigurationsänderung auftritt , z. B. wenn ein Gerät gedreht wird, wiederholt der Code den Prozess. Um die ursprünglich abgerufenen Ergebnisse wiederzuverwenden und keine unnötigen, redundanten Netzwerkaufrufe zu verursachen, können OnRetainNonconfigurationInstance
wir die Ergebnisse wie folgt speichern:
public class NonConfigInstanceActivity : ListActivity
{
TweetListWrapper _savedInstance;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
var tweetsWrapper = LastNonConfigurationInstance as TweetListWrapper;
if (tweetsWrapper != null) {
PopulateTweetList (tweetsWrapper.Tweets);
} else {
SearchTwitter ("xamarin");
}
public override Java.Lang.Object OnRetainNonConfigurationInstance ()
{
base.OnRetainNonConfigurationInstance ();
return _savedInstance;
}
...
void PopulateTweetList (string[] results)
{
ListAdapter = new ArrayAdapter<string> (this, Resource.Layout.ItemView, results);
_savedInstance = new TweetListWrapper{Tweets=results};
}
}
Wenn das Gerät nun gedreht wird, werden die ursprünglichen Ergebnisse aus der LastNonConfiguartionInstance
-Eigenschaft abgerufen. In diesem Beispiel bestehen die Ergebnisse aus einem string[]
, das Tweets enthält. Da OnRetainNonConfigurationInstance
erfordert, dass ein Java.Lang.Object
zurückgegeben werden muss, wird in string[]
eine Klasse umschlossen, die unterklassigt Java.Lang.Object
, wie unten gezeigt:
class TweetListWrapper : Java.Lang.Object
{
public string[] Tweets { get; set; }
}
Wenn Sie z. B. versuchen, ein TextView
als Objekt zu verwenden, das von OnRetainNonConfigurationInstance
zurückgegeben wird, wird die Aktivität verloren, wie im folgenden Code veranschaulicht:
TextView _textView;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
var tv = LastNonConfigurationInstance as TextViewWrapper;
if(tv != null) {
_textView = tv;
var parent = _textView.Parent as FrameLayout;
parent.RemoveView(_textView);
} else {
_textView = new TextView (this);
_textView.Text = "This will leak.";
}
SetContentView (_textView);
}
public override Java.Lang.Object OnRetainNonConfigurationInstance ()
{
base.OnRetainNonConfigurationInstance ();
return _textView;
}
In diesem Abschnitt haben wir gelernt, wie Einfache Zustandsdaten mit Bundle
beibehalten und komplexere Datentypen mit beibehalten werden OnRetainNonConfigurationInstance
.
Zusammenfassung
Der Lebenszyklus von Android-Aktivitäten bietet ein leistungsstarkes Framework für die Zustandsverwaltung von Aktivitäten innerhalb einer Anwendung, aber es kann schwierig sein, sie zu verstehen und zu implementieren. In diesem Kapitel wurden die verschiedenen Zustände vorgestellt, die eine Aktivität während ihrer Lebensdauer durchlaufen kann, sowie die Lebenszyklusmethoden, die diesen Zuständen zugeordnet sind. Als Nächstes wurde eine Anleitung dazu bereitgestellt, welche Art von Logik in den einzelnen Methoden ausgeführt werden sollte.