Mobile Themen

Windows Phone 7-Tombstoning

Jaime Rodriguez

Beispielcode herunterladen

Eine solide mobile Plattform sollte die Hardware-Einschränkungen berücksichtigen, die sich für das Gerät aufgrund der Mobilität ergeben. Im Vergleich zu Desktops verfügen mobile Geräte über weniger Speicherkapazität, geringere Verarbeitungsleistung, begrenzte Bildschirmfläche und eingeschränkte Akkulebensdauer. Wenn Sie diese Einschränkungen zusammenfassen, sollten Sie zu dem Schluss kommen, dass auf einem nicht dedizierten Gerät, auf dem viele Anwendungen ausgeführt werden, einige Anwendungen letztendlich geschlossen oder heruntergefahren werden, um Ressourcen für andere Anwendungen freizugeben.

Windows Phone beseitigt diese Einschränkungen mittels einer Funktion namens Tombstoning. Es mag zwar den Anschein haben, dass Tombstoning eine extrem einfache Lösung ist, tatsächlich sorgt diese Funktion jedoch für einen Konflikt unter den Entwicklern. Einige meinen, Tombstoning sollte nicht erforderlich sein. Andere argumentieren, Tombstoning sei zu schwierig. Dem Rest von uns gefällt einfach der Name der Funktion nicht. Nichtsdestotrotz wird diese Funktion aufgrund der Einschränkungen von mobilen Geräten zum notwendigen Übel, sodass umfangreiche mobile Anwendungen in der Lage sein müssen, Tombstoning zu bewältigen.

Lebenszyklus der Windows Phone-Anwendung

Die meisten neuen Windows Phone-Entwickler rufen diese Plattform in der Erwartung auf, dass der Lebenszyklus einer Anwendung ungefähr so aussieht: 

  1. Start
  2. Ausführen
  3. Beenden
  4. Zu Schritt 1 wechseln und erneut starten

Windows Phone 7 stellt diese Erwartung infrage, indem ein anderer Lebenszyklus dargelegt wird: ein Lebenszyklus, der weniger prozessorientiert und mehr sitzungsorientiert ist.

Mit Windows Phone 7 können Sie sich den Lebenszyklus so vorstellen:

  1. Start
  2. Ausführen
  3. Unterbrochene Ausführung oder Beenden
  4. Bei Unterbrechung erneut versuchen oder sogar unterbrochene Anwendung erneut starten
  5. Falls die Anwendung beendet wurde, erneut starten 

Die Vorteile dieses neuen sitzungsorientierten Modells besteht darin, dass Benutzer in Anwendungen navigieren können, ohne sich Gedanken machen zu müssen, wie das Betriebssystem seine Ressourcen verwaltet. Einem Benutzer ist es egal, wenn durch die Unterbrechung des Spiels, um auf eine eingehende SMS zu antworten, der Prozess für das Spiel beendet wird. Der Benutzer sollte erwarten, dass er zum Spiel zurückkehren kann, sobald er die SMS geschrieben und gesendet hat. Wenn dieses Prinzip ausreichend gut funktioniert, spielen die zugrunde liegenden Details keine Rolle.

Der Nachteil für Entwickler besteht darin, dass es etwas mehr zu bewältigen gibt, um die Wahrnehmung der Sitzungskontinuität wirklich bereitzustellen, da Ihre Sitzungen nach wie vor auf einem herkömmlichen, prozessorientierten Betriebssystem ausgeführt werden. Damit Sitzungen in prozessorientierten Betriebssystemen aufgenommen werden können, erstellen Sie logische Zustände für die Sitzung: „Launched“, „Activated“, „Running“, „Deactivated“, „Tombstoned“ und „Closed“ (oder „Ended“).

Abbildung 1 zeigt den praktischen Lebenszyklus für eine Windows Phone 7-Anwendung. Die in Abbildung 2 beschriebenen Lebenszyklusereignisse der Anwendung werden durch die Microsoft.Phone.Shell.PhoneApplicationService-Klasse verfügbar gemacht. 

Windows Phone 7 Application Lifecycle

Abbildung 1 Lebenszyklus der Windows Phone 7-Anwendung

Abbildung 2 Lebenszyklusereignisse der Anwendung

Logischer Status PhoneApplicationService-Ereignis Beschreibung
Launched Wird gestartet Die Anwendung wird gestartet, wenn der Benutzer das Start-Symbol bzw. das Anwendungslisten-Symbol drückt oder auf eine Toastbenachrichtigung klickt. Mit „Launched“ wird die Sitzung neu gestartet.
Activated Aktiviert Die Anwendung wird aktiviert, wenn der Benutzer die Taste „Zurück“ drückt und die zuvor deaktivierte Anwendung wieder in den Vordergrund stellt. In diesem Fall geht der Benutzer davon aus, zu einer laufenden Sitzung zurückzukehren.
Running Wird ausgeführt Nach dem Start oder der Aktivierung der Anwendung wird sie ausgeführt. 
Deactivated Deaktiviert Eine aktuell ausgeführte Anwendung wird deaktiviert, wenn die Vordergrundverarbeitung von dieser Anwendung an eine andere Anwendung oder an eine Betriebssystemkomponente übertragen wird (wie zum Beispiel an ein Auswahl- bzw. Startprogramm oder an den Bildschirm „Sperre“). Die Sitzung wird unterbrochen, jedoch voraussichtlich zu einem späteren Zeitpunkt fortgesetzt.
Ended (oder Exited) Wird geschlossen

Der Benutzer beendet die Anwendung durch Drücken der Taste „Zurück“ auf der Hauptseite.

In diesem Fall geht der Benutzer davon aus, zu einer vollkommen neuen Anwendung zurückzukehren.

Der Status „Tombstoned“ ist etwas komplizierter und bezieht sich nicht direkt auf ein PhoneApplicationService-Ereignis. Wenn eine Anwendung deaktiviert wird, beendet das Betriebssystem nicht unverzüglich den Prozess für diese Anwendung. Theoretisch beendet das Betriebssystem die Anwendung, wenn Ressourcen benötigt werden und dieser Fall eintritt. Die Anwendung erhält keine Benachrichtigung und wird einfach beendet.  

Praktisch beendet Windows Phone 7 den Prozess schnell nach dem Übertragen der Steuerung an eine andere Vordergrundanwendung. Hierauf sollten Sie sich jedoch nicht verlassen. Microsoft hat bereits im Februar auf dem Mobile World Congress Verbesserungen wie Fast App Switching (Schnelle Anwendungsumschaltung) angekündigt. Verlassen Sie sich also nicht auf ein Implementierungsdetail, mit dem festgelegt wird, wann Tombstoning erfolgt. Bereiten Sie sich stattdessen hierauf vor, indem Sie die richtigen Schritte bei der Deaktivierung ausführen.

Deaktiviert im Vergleich zu Tombstoned

Bei einem Telefon werden viele Prozesse fortwährend ausgeführt (Shell, Telefon usw.), aber es wird höchstens eine Anwendung im Vordergrund ausgeführt. (Bei einem Telefon können auch gar keine Prozesse stattfinden, wenn keine Anwendung im Vordergrund ausgeführt wird.)

Wenn eine Vordergrundanwendung die Steuerung an eine andere Anwendung oder an eine Betriebssystemkomponente überträgt, wird der Prozess deaktiviert. Nach der Deaktivierung des Prozesses wird dieser möglicherweise vom Betriebssystem beendet, um Ressourcen freizugeben. Dies wird als Tombstoning bezeichnet. 

Wie Sie sehen, erfolgt Tombstoning nicht bei jeder Deaktivierung der Anwendung, jedoch stets nach einer Deaktivierung. Tatsächlich ist „Deactivated“ das letzte Ereignis, das von PhoneApplicationService vor dem Tombstoning ausgelöst wird. Folglich müssen Sie Ihre Arbeit hier beginnen, um die Anwendung zu einem späteren Zeitpunkt erneut zu aktivieren.

In Abbildung 3 werden alle unterschiedlichen Aufgaben angegeben, die zur Deaktivierung führen, und die Wahrscheinlichkeit des Eintretens von Tombstoning geschätzt. 

Abbildung 3 Aufgaben, die eine Deaktivierung auslösen

Aktion Deaktiviert? Tombstoned?
Der Benutzer drückt die Taste „Zurück“ auf der ersten Seite der Anwendung. Nein. Hierdurch wird die Anwendung geschlossen. Nein. Eine Deaktivierung hat nicht stattgefunden.
Der Benutzer drückt die Taste „Start“. Ja Sehr wahrscheinlich, jedoch nicht garantiert. Einige Sekunden nach der Deaktivierung der Anwendung erfolgt das Tombstoning. Wenn der Benutzer die Anwendung kurz nach der Deaktivierung wieder aufruft, ist möglicherweise noch kein Tombstoning erfolgt. Dies könnte als unbestimmtes Timeout bezeichnet werden.
Der Benutzer ruft ein Auswahl- oder Startprogramm auf, für das ein Tombstoning erfolgt. Ja Sehr wahrscheinlich, jedoch tritt ein Timeout auf.
Der Benutzer ruft ein Auswahl- oder Startprogramm auf, für das kein Tombstoning erfolgt. Ja Weniger wahrscheinlich, dennoch kann es auftreten. Wenn der Benutzer die Taste „Start“ während der Ausführung der Aufgabe drückt, wird die Regel „Der Benutzer drückt die Taste ’Start’“ angezeigt. Ein neues Ereignis mit dem Status „Deactivated“ wird nicht ausgelöst, da die Anwendung bereits deaktiviert wurde. 
Der Bildschirm „Sperre“ wird geöffnet. Die Anwendung ist nicht konfiguriert, um im gesperrten Bildschirm ausgeführt werden zu können. Ja Sehr wahrscheinlich, jedoch tritt ein Timeout auf.
Eine Toastbenachrichtigung geht ein und der Benutzer tippt sie an, sodass eine andere Vordergrundanwendung geöffnet wird. Ja Sehr wahrscheinlich, jedoch tritt ein Timeout auf.

Es gibt eine Untergruppe von Auswahlprogrammen, für die nicht unverzüglich ein Tombstoning erfolgt. Es kann jedoch weiterhin ein Tombstoning stattfinden, wenn der Benutzer eine Aktion ausführt, durch die der Prozess ein Tombstoning erfährt. Hierzu gehören PhotoChooserTask (es sei denn, der Benutzer gibt „Zuschneiden“ an), CameraCaptureTask, MediaPlayerLauncher, EmailAddressChooserTask und PhoneNumberChooserTask.

Für alle anderen Auswahl- und Startprogramme erfolgt unverzüglich nach Aufruf der Show-Methode ein Tombstoning.

Um den Lebenszyklus der Windows Phone 7-Anwendung in Aktion zu sehen, starten Sie das LWP.TombStoning-Beispiel im Codedownload. 

Speichern und Wiederherstellen des Status

Da das Ziel für eine sitzungsbasierte Navigation darin besteht, dem Benutzer den problemlosen Wechsel in Vordergrundanwendungen zu erleichtern, müssen Sie alle relevanten Zustände im Ereignis „Deactivated“ speichern und den Status im Ereignis „Activated“ wiederherstellen. Die meisten Anwendungen verfügen über drei Arten von zu verwaltenden Zuständen:

  • Der persistente Anwendungsstatus muss stets fortbestehen. Hierzu gehören die Anwendungseinstellungen, Benutzerdaten usw.
  • Der sitzungsspezifische Anwendungsstatus umfasst temporäre Zustände wie zum Beispiel Caches und ViewModels, die bei der Aktivierung wiederhergestellt werden müssen, jedoch bei einem neuen Start der Anwendung erneut gestartet werden.
  • Der UI- oder seitenspezifische Status ist beim Aktivieren einer Anwendung zur Wiederherstellung von PhoneApplicationPage erforderlich. Windows Phone 7 speichert beim Tombstoning den Backstack für eine Anwendung. Bei der Aktivierung wird nur die letzte Seite wiederhergestellt, die vor dem Tombstoning der Anwendung aktiv war. Wenn der Benutzer die Taste „Zurück“ drückt, wird die vorherige Seite instanziiert.

Der persistente Anwendungsstatus sollte in IsolatedStorage oder über die ApplicationSettings-Klasse gespeichert werden. Der Anwendungsstatus sollte so früh wie möglich gespeichert werden, für den Fall, dass zum Beispiel die Akkuleistung nachlässt. 

Wenn es sich um Benutzerdaten handelt (beispielsweise um ein Sitzungscache), für die nicht allzu häufig eine Serialisierung durchgeführt werden soll, sollten die Daten in den Ereignissen „Deactivated“ und „Closing“ gespeichert und (symmetrisch) in den Ereignissen „Activated“ oder „Launching“ wiederhergestellt werden.

Der sitzungsspezifische Status kann in einem isolierten Speicher gespeichert werden, wenn Sie die Kontrolle über die Serialisierungsformate wünschen oder zu viele Daten vorhanden sind. Es ist auch möglich, den Status im PhoneApplicationService.State-Wörterbuch zu speichern. Dieser Status sollte nur im Ereignis „Deactivated“ gespeichert und im Ereignis „Activated“ wiederhergestellt werden.

Der seitenspezifische Status sollte im PhoneApplicationPage.State-Wörterbuch gespeichert werden. Beim Speichern des seitenspezifischen Status sollte unbedingt darauf geachtet werden, dass die Anwendung einen Backstack von Seiten aufweist, die beim Auftreten von PhoneApplicationService.Deactivated automatisch serialisiert werden. Um Ihre Seiten für Tombstoning bereitzuhalten, müssen Sie die PhoneApplicationPage.OnNavigatedFrom-Überschreibung in Ihrer Seite überwachen und jeglichen Ansichtsstatus, der noch nicht an Ihr Modell (oder ViewModel) übergeben wurde, im Wörterbuch der Seite speichern. Warten Sie nicht, bis das Ereignis „Deactivated“ eintritt, da Sie ansonsten die Seiten im Backstack nicht mehr aufrufen können.

Wenn Sie beim Empfang von OnNavigatedFrom den Seitenstatus speichern, sollten Sie ihn natürlich in der OnNavigatedTo-Überschreibung für die Seite wiederherstellen.

Sie könnten den seitenspezifischen Status auch in ViewModels speichern und dann Ihre ViewModels als Sitzungsstatus serialisieren. Dies setzt jedoch voraus, dass ein Status ohne Commit für einen ViewMode gespeichert wird. Aus diesem Grund rate ich von dieser Methode ab. Nutzen Sie die vorhandene Infrastruktur, um für spätere Optimierungen der Plattform zukunftssicher zu bleiben.

Vermeiden von Fehlerquellen

Tombstoning ist nicht schwierig. Es ist einfach nur ein bisschen aufwändig und setzt Konsistenz und Planung voraus. Wenn Ihre Anwendung deaktiviert wurde, jedoch kein Tombstoning erfolgte, verbleibt Ihr Status im Speicher und wird nicht rekonstruiert. 

Verlassen Sie sich nicht auf Klassenkonstruktoren, mit denen der für Ihre Anwendung erforderliche Status erstellt wird, die jedoch während der Deaktivierung möglicherweise freigegeben werden. Die Symmetrie ist zu bevorzugen. Verwenden Sie die Ereignisse „PhoneApplicationService.Deactivated“ und „PhoneApplicationService.Activated“ für den Status auf Anwendungsebene sowie „OnNavigatedFrom“ oder „OnNavigatedTo“ für den seitenspezifischen Status. 

Wenn Ihre Anwendung Objekte (Singletons) enthält, die außerhalb der Aktivierungsaufrufe instantiiert werden (möglicherweise aufgrund einer verzögerten Instanziierung), prüfen Sie stets, ob diese ordnungsgemäß erstellt und initialisiert wurden, bevor Sie sie verwenden. Ein häufiger Fehler, über den ich gestolpert bin, ist das Lesen von Daten im Ereignis „PhoneApplicationService.Activated“ oder in „PhoneApplicationPage.OnNavigatedTo“, ohne die Daten zurückzusetzen. Für die Seiten kann NavigatedTo mehrmals ausgeführt werden (ungeachtet vom Tombstoning). Während einer Sitzung kann ein Tombstoning sogar mehrmals für eine Sitzung erfolgen.

Nachdem Sie den Status wiederhergestellt haben, löschen Sie ihn. Sie können ihn später in der NavigatedFrom-Überschreibung für Ihre Seite oder im Ereignis „Deactivated“ für die Anwendung festlegen.

Handeln Sie intelligent hinsichtlich dessen, was Sie speichern und wann Sie es wiederherstellen. Dem Benutzer das problemlose Zurückkehren zur Anwendung zu erleichtern, besteht teilweise darin, Ihre Anwendung unverzüglich wiederherzustellen. Wenn Sie zu viel vom Seiten- oder Anwendungsstatus speichern, wird die Aktivierung verlangsamt. Nutzen Sie gegebenenfalls den isolierten Speicher, um den Status, den Sie möglicherweise nicht unverzüglich beim Aktivieren der Anwendung benötigen, im Hintergrund zu laden. Sowohl die Aktivierung als auch die Deaktivierung sollten in weniger als 10 Sekunden geschehen. Achten Sie auf diese Zeitspanne, oder das Betriebssystem beendet Ihren Prozess, bevor die Deaktivierung beendet wurde oder während die erneute Aktivierung ausgeführt wird. Diese Prozesse sollten jedoch wesentlich weniger als 10 Sekunden dauern.

Machen Sie sich mit den Einschränkungen des Serialisierungsframework vertraut. Sie können maximal rund 2 MB in Ihrem gesamten Seiten- und Anwendungsstatus speichern. Wenn Sie diese Speichergrenze überschreiten, treten beim Navigieren und Deaktivieren Ausnahmen auf. Sie sollten solche Datenmengen nicht im seitenspezifischen Status serialisieren. Wenn Sie umfangreiche Datensätze zwischenspeichern müssen, ist es besser, sie im isolierten Speicher zu speichern.

Verwenden Sie Abfragezeichenfolgen für die Seitennavigation. Wenn Sie Kontext in eine neue Seite übertragen müssen, verwenden Sie die an die Seite weitergeleitete Abfragezeichenfolge so, dass entweder alle Daten oder ein eindeutiger Bezeichner (ein Token) an einen Dienstlocator weitergeleitet werden, der die Daten anhand des Token abrufen kann. Gehen Sie nicht davon aus, dass ViewModels oder der seitenspezifische Status verfügbar sind, wenn Ihre Seiten nach dem Tombstoning aktiviert werden.

Machen Sie sich mit Ihren Auswahl- und Startprogrammen vertraut. Nicht alle erfahren ein Tombstoning, und es gibt spezifische Regeln zum Einbinden von Ereignislistener für Auswahlprogramme. Um weitere Informationen zu diesen Regeln zu erhalten, lesen Sie den Artikel „How to: Use Choosers for Windows Phone“ unter bit.ly/edEsGQ.

Denken Sie an die Beziehung zwischen OnNavigatedTo und PhoneApplicationPage.Loaded. In OnNavigatedTo wurde die visuelle Struktur der Seite noch nicht vollständig erstellt. Oftmals müssen Sie den wiederhergestellten Status extrahieren, warten Sie jedoch auf das Ereignis „Loaded“ der Seite, um den UI-Status wiederherzustellen. Die Aktionen, die verzögert werden müssen, umfassen zum Beispiel das Festlegen des Schwerpunkts oder das Festlegen von SelectedIndex in einem Pivot oder Bildlauf.

Wenn Sie viel Zeit zum Speichern und Wiederherstellen von Daten aufwenden – was Sie eigentlich nicht sollten – erwägen Sie erweiterte Optimierungen. Diese sollten Sie jedoch nur erwägen, wenn es absolut erforderlich ist. Vergessen Sie auch nicht, die optimierten Funktionen gründlich zu testen.

Zum Erkennen von Tombstones setzen Sie unter „Deactivated“ ein Flag in Ihrer Anwendungsklasse. Wenn das Flag beim Aktivieren nicht zurückgesetzt wird, bedeutet dies, dass kein Tombstoning durchgeführt wurde und all Ihre Seiten weiterhin im Speicher vorhanden sein müssten, sodass keine Wiederherstellung erforderlich ist. Zum Kombinieren des Flags mit der Erkennung für Tombstoning in den Seiten können Sie für jede Aktivierung innerhalb einer Sitzung ein Token verwenden.

Eine andere Optimierungsmethode besteht darin, die OnNavigatingFrom-Überschreibung der Seite zu überwachen und die Richtung zu ermitteln. Wenn NavigationMode erneut aufgerufen wird, wird die Seite zerstört, und es gibt keinen Grund, ihren Status zu speichern.

Ich betone noch einmal, dass für einwandfreies Tombstoning eine Planung das Entscheidende ist. Bewahren Sie sich Tombstoning nicht bis zum Ende des Entwicklungszyklus der Anwendung auf, um dann zu versuchen, diese Funktion nachträglich einzubinden. Planen Sie die Tombstoning-Funktion frühzeitig, implementieren Sie sie während Ihrer Arbeit und testen Sie sie gründlich. 

Sie können Großartiges erreichen

Einen letzten Tipp gebe ich Entwicklern noch: Sie sollten die Tombstoning-Erfahrung problemlos gestalten. Die Windows Phone 7-Steuerelemente ermöglichen eine leichte Navigation in einer Seite. Um diesen Vorgang wirklich nahtlos für den Benutzer ablaufen zu lassen – um ihm das Gefühl zu vermitteln, er hätte nie eine Seite oder Anwendung beendet – sollten Sie Folgendes wiederherstellen:

  • SelectedIndex für den Pivot (sofern die Seite einen Pivot enthält)
  • Bildlaufposition in einem Listenfeld oder einem beliebigen anderen ScrollViewer auf der Seite.
  • Zoomstufen und andere Transformationen in einem Kartensteuerelement, einem Bildanzeiger oder einem beliebigen anderen Steuerelement, das Bearbeitungen unterstützt.
  • Text ohne Commit in einem Textfeld. Wenn das Textfeld für die Anwendung unerlässlich ist (der Tweet-Text in einer Twitter-Anwendung zum Beispiel), sollten die Textauswahl, die Caret-Position und der Schwerpunkt wiederhergestellt werden.
  • Element, dessen Schwerpunkt auf einer Seite lag (insbesondere bei einem Textfeld, das die SIP zeigen muss).

Die SelectedItem-Eigenschaft in einem Panorama sollte jedoch nicht wiederhergestellt werden. Das Panorama unterstützt diese Eigenschaft nicht. Das Festlegen von DefaultItem in einem Panorama ist nicht identisch mit Verschieben in die richtige Seite. Ich rate Ihnen davon ab, DefaultItem zum Zurückkehren zu dem Panoramaelement zu verwenden, das vor dem Tombstoning ausgewählt wurde.

Um diese Tipps in Aktion zu sehen, starten Sie das LPW.TombstoningWithState-Beispiel im Codedownload. Die Datei „readme.txt“ enthält Zeiger und Skripts für jedes Szenario.

Einige Bemerkungen zum Schluss

Dieser Artikel ist keinesfalls eine umfassende Referenz für Tombstoning. Aber da Sie nun wissen, worauf Sie achten müssen, fügen Sie einige Tombstoning-Muster in Ihre eigenen Windows Phone 7-Anwendungen ein. Ich bin überzeugt, dass Sie sofort feststellen, wie sehr sich Ihre Benutzererfahrung hierdurch verbessert.

Jaime Rodriguezist ein Hauptexperte bei Microsoft für neue Client-Technologien wie Silverlight und Windows Phone 7. Sie erreichen ihn über Twitter unter twitter.com/jaimerodriguez oder lesen Sie seinen Blog unter blogs.msdn.com/jaimer.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Peter Torr