Suspension Manager

Nein es geht nicht um Frührente. der Lebenszyklus von Windows 8 METRO Anwendungen etwas eigenwillig. Kurz gesagt, kann man das Betriebssystem einen in den Hintergrund gelegte Anwendung aus dem Betriebssystem Sheduler entfernen. Der Modus nennt sich suspended.

image

warum und wieso dauert etwas länger zu erklären.  Relevant ist, was man aus Coding Sicht tun muss.

Eigentlich muss man gar nichts tun. Die Anwendung wird ja nicht geschlossen, insofern kommt sie in dem Status zurück wie man sie zuletzt gesehen hat. Eine Textbox beinhaltet noch immer den Text. Aber Windows 8 hat das rechteine Suspended APP komplett zu entfernen. Ich habe das zwar noch nie gesehen, aber  bei kommenden ARM Geräten mit wenig Arbeitsspeicher wird das wohl passieren.

Sämtliche Beispiele aus dem SDK enthalten eine Hilfsklasse die sich SuspensionManager nennt.Ich kopiere die aktuell in meine Projekte, auch wenn sie nicht optimal ist.

Module SuspensionManager
    Private sessionState_ As New Dictionary(Of String, Object)
    Private knownTypes_ As List(Of Type) = New List(Of Type)
    Private Const filename As String = "_sessionState.xml"

    ' Provides access to the currect session state
    Public ReadOnly Property SessionState As Dictionary(Of String, Object)
        Get
            Return sessionState_
        End Get
    End Property

    ' Allows custom types to be added to the list of types that can be serialized
    Public ReadOnly Property KnownTypes As List(Of Type)
        Get
            Return knownTypes_
        End Get
    End Property

    ' Save the current session state
    Public Async Function SaveAsync() As Task
        ' Get the output stream for the SessionState file.
        Dim file As StorageFile = 
Await ApplicationData.Current.LocalFolder.CreateFileAsync(filename,
CreationCollisionOption.ReplaceExisting) Dim raStream As IRandomAccessStream =
Await file.OpenAsync(FileAccessMode.ReadWrite) Using outStream As IOutputStream = raStream.GetOutputStreamAt(0) ' Serialize the Session State. Dim serializer As New
DataContractSerializer(GetType(Dictionary(Of String, Object))) serializer.WriteObject(outStream.AsStreamForWrite, sessionState_) Await outStream.FlushAsync End Using End Function ' Restore the saved sesison state Public Async Function RestoreAsync() As Task ' Get the input stream for the SessionState file. Try Dim file As StorageFile =
Await ApplicationData.Current.LocalFolder.GetFileAsync(filename) If file Is Nothing Then Exit Function End If Dim inStream As IInputStream = Await file.OpenSequentialReadAsync ' Deserialize the Session State. Dim serializer As New DataContractSerializer(GetType(Dictionary(Of String, Object))) sessionState_ = CType(serializer.ReadObject(inStream.AsStreamForRead),
Dictionary(Of String, Object)) Catch ex As Exception ' Restoring state is best-effort.
If it fails, the app will just come up with a new session. End Try End Function End Module

In der Applikation Klasse app.xaml.vb wird dann diese aufgerufen wenn die Anwendung schlafen geht oder wieder aufwacht.

Protected Async Sub OnSuspending(ByVal sender As Object, 
ByVal args As SuspendingEventArgs) Handles Me.Suspending Dim deferral As SuspendingDeferral = args.SuspendingOperation.GetDeferral Await SuspensionManager.SaveAsync deferral.Complete() End Sub Protected Overrides Async Sub OnLaunched(ByVal args As LaunchActivatedEventArgs) If args.PreviousExecutionState = ApplicationExecutionState.Terminated Then ' Do a synchronous restore Await SuspensionManager.RestoreAsync End If

Spannend ist der Part in dem man per Getdeferral WinRT bittet die Anwendung vom Suspending zu verschonen. Schließlich kann das speichern ja etwas länger dauern und damit wird der 5 Sekunden Zyklus unterbrochen.

Ob die Anwendung vom Suspended oder Terminated Modus kommt, spielt für das Restore der Settings natürlich eine Rolle.

Im eigentlichen VB.NET Programmcode wird auch der Suspensionmanager um einer Art Session wie in ASP.NET relevanten Infos abzulegen. So kann das ausgewählte Listenelement  wieder hergestellt werden.

If SuspensionManager.SessionState.ContainsKey("SelectedScenario") Then
            Dim selectedScenarioName As String = 
TryCast(SuspensionManager.SessionState("SelectedScenario"), String) startingScenario =
TryCast(Me.FindName(selectedScenarioName), ListBoxItem) End If

Kommentare (6) -

Rainer
03.08.2012 15:07:51 #

Hallo Hannes!

Bist du dir sicher, dass mit SuspendingOperation.GetDeferral die 5 Sekunden Zeitmaximum zum Speichern des Anwendungsstatus verlängert wird? Meines Wissens nach ist das Deferral-Objekt notwendig wegen dem async Call auf SuspensionManager.SaveAsync. Der beendet schließlich die OnSuspending-Methode und WinRT könnte glauben, dass das Speichern des States fertig ist. Durch das Deferral-Objekt teile ich meines Wissens WinRT mit, dass die OnSuspending-Methode zwar erstmal durch ist, dass das Abspeichern des Status aber noch läuft (bis deferral.Complete).

lg,
Rainer.

Hannes Preishuber
03.08.2012 15:20:33 #

Hi Rainer
guter Hinweis. Nein ich bin mir nicht sicher. Die Doku schweigt sich aus msdn.microsoft.com/.../...eration.getdeferral.aspx
soweit meine Tests damals (müsste Consumer Preview gewesen sein) ergaben, kann der Vorgang so auf 10 Sekunden hinausgezögert werden um zb einen Webservice Call abzusetzen.

Rainer
03.08.2012 15:24:18 #

Das mit dem Webservice-Call stimmt glaube ich beim Suspending nicht. Dort geht es um "Wallclock-Time". Bei Background Tasks geht es um CPU-Time -> async Webservice-Calls zählen nicht. Habe in meinen Metro-Slides gesucht und folgendes gefunden: "You have 5 seconds real time (not CPU time) to save what you need to save. If you take too long, the App will be terminated. Even when you use deferal for asynchronous processing."

lg,
Rainer.

Rainer
03.08.2012 15:25:23 #

Sorry, war unklar formuliert. "Meine Slides" heißt nicht Slides, die ich gemalt habe; ich meine Metro-Slides, die ich von MS bekommen hab.

Max
12.09.2012 10:55:00 #

Der Beitrag hat mir leider überhaupt nicht geholfen. Keine Hintergrund-Informationen, dazu noch massig Fehler #fail

Hannes
12.09.2012 11:00:28 #

Also in der finalen Version sind definitiv 5 Sekunden (wie Rainer korrekt anmerkt)

Kommentare sind geschlossen