App Windows 8, suspending e resuming dello stato
Una delle cose che ho trovato più complicate da capire quando si sviluppa un’app per Windows 8 Metro-style è la gestione del suspending e del resuming. Non perchè sia di per sè complicata, quanto perchè se aprite Visual Studio 2012 e iniziate con un qualsiasi progetto per il Windows Store, vi viene già fornita un set di classi che – sotto sotto – fanno il lavoro sporco di salvataggio e di recupero dei dati. Quindi secondo me non si capisce esattamente cosa faccia davvero il sistema operativo di base, e cosa invece viene fatto dal template classico di un’app Windows Store.
Andiamo con calma. Supponiamo di dover fare una semplice app Metro che chiede all’utente tre informazioni: cognome, nome e data di nascita. Il tutto avviene in modo molto semplice, con tre TextBox. Aprite Visual Studio 2012, cominciate con un progetto scegliendo il template “Blank App (XAML)”, che si trova all’interno dei folder Visual C# –> Windows Store. Editiamo la MainPage.xaml ed incollate questo:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="Cognome" FontSize="34" VerticalAlignment="Center" Margin="4" /> <TextBlock Grid.Row="1" Grid.Column="0" Text="Nome" FontSize="34" VerticalAlignment="Center" Margin="4" /> <TextBlock Grid.Row="2" Grid.Column="0" Text="Data di Nascita" FontSize="34" VerticalAlignment="Center" Margin="4" /> <TextBox Grid.Row="0" Grid.Column="1" Text="Damiani" x:Name="Cognome" FontSize="32" VerticalAlignment="Center" Foreground="Black" Margin="4" /> <TextBox Grid.Row="1" Grid.Column="1" Text="Igor" x:Name="Nome" FontSize="32" VerticalAlignment="Center" Foreground="Black" Margin="4" /> <TextBox Grid.Row="2" Grid.Column="1" Text="01/01/1900" x:Name="DataNascita" FontSize="32" VerticalAlignment="Center" Foreground="Black" Margin="4" /> </Grid>
Nulla di insolito. Per ora evitiamo MVVM. Abbiamo messo tre TextBox, ciascuna con il suo nome. Adesso, facciamola girare ed osserviamone il comportamento.
- All’avvio vi vengono ovviamente proposti i valori di default cablati nello XAML (il mio nome, cognome, e la mia data di nascita falsa)
- Provate a cambiare tali valori, scrivendoci i vostri, o quello che volete
- Tornate in Visual Studio a suon di Alt+Tab e – utilizzando la toolbar Debug Location cliccate sull’opzione Suspend and Shutdown: questa opzione simula il fatto che Windows termina la vostra app perchè ha bisogno di memoria, o per qualsiasi altro motivo. Ad esempio, se passate da un’app Metro all’altra, quella che finisce in background viene sospesa, per non consumare memoria, batteria, etc. etc.
- Se avete fatto correttamente il passo (3), l’app viene terminata: Visual Studio ed il suo debugger terminano ovviamente la sua esecuzione
- Se rilanciate l’app, DEVE accadere una cosa molto importante: l’app parte ma NON DEVE riproporre i valori di default, ma deve recuperare il precedente stato!!
A questo punto è necessario soffermarsi sul punto (5). Per chi viene da un avanzato sviluppo di app Windows Phone come me, troverà una notevole differenza. Quando toccate una tile su Windows Phone, l’app parte SEMPRE da zero, senza alcun bisogno di restorare il precedente stato. Questo NON E’ VERO con Windows 8. Il motivo è presto detto: con Windows Phone non potete chiudere manualmente l’app, mentre con Windows 8 sì. Con Windows 8, fin tanto che non la chiudete, essa deve SEMPRE recuperare lo stato che l’utente aveva. In breve: con il nostro piccolo test di prima l’app è stata sospesa (ovvero: non l’abbiamo volutamente chiusa), per cui se la rilanciamo (dalla tile sulla Start Page oppure prendendola dalle app aperte, usando lo charm sulla sinistra dello schermo) essa deve recuperare lo stato, proponendoci non i valori di default, ma quelli che avevamo modificato. Questo adesso ovviamente non accade, perchè in questo momento il meccanismo di suspending & resuming nella nostra piccola app di prova non esiste, perchè non è stato ancora implementato. Ma è stato importante capire, secondo me, cosa succede by default, e cosa invece dobbiamo implementare.
Andiamo avanti.
Suspending, salvataggio delle informazioni
Diamo un’occhiata al costruttore della classe App, contenuto nel file App.xaml.cs. Esso sottoscrive l’evento Suspending:
this.Suspending += OnSuspending;
L’handler di questo evento fa una cosa semplice:
private async void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); await this.SaveCurrentState(); deferral.Complete(); }
La parte più interessante è il this.SaveCurrentState(), che fa una cosa di cui magari parleremo in un altro post. Questo metodo viene eseguito ogni qualvolta il sistema operativo manda in sospensione la nostra app: lo scopo quindi è quello di salvare lo stato, con tutto ciò che comporta. Caselle di testo, contenuto di ListBox, viewmodel, etc. etc.: tutto ciò che serve per dare l’illusione che l’app non si sia mai chiusa, insomma. Ed il tutto deve avvenire – se ben ricordo – nell’arco di 5 secondi: trascorso questo tempo, Windows killa la nostra app e tutto è perduto.
Resuming, recupero delle informazioni
Ovviamente deve esistere anche l’operazione inversa. Quando l’app viene lanciata potrebbe essere necessario recuperare le informazioni e riadattare la view dell’utente secondo quanto salvato. Diamo un’occhiata a:
protected async override void OnLaunched(LaunchActivatedEventArgs args) { }
Ad un certo punto troverete una riga di codice simile alla seguente:
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) { await this.RestoreLastState(rootFrame); }
La proprietà PreviousExecutionState ci dice la modalità con cui è stata chiusa l’app: nel caso fosse Terminated (ovvero chiusa dal sistema operativo) allora dobbiamo recuperare lo stato. Negli altri casi (ClosedByUser, NotRunning, Running, Suspended) no. Nel mio caso ho implementato un metodo RestoreLastState che fa tutto il lavoro.
Conclusioni
Quello che mi ha confuso per un po’ di tempo è il fatto che se usate un altro template per il Windows Store (Grid App, Split App, etc.) vi viene già fornita una classe SuspensionManager che fa buona parte del lavoro, con il fatto però che non ho mai capito cosa facesse il sistema operativo nativamente, e quanto invece facesse l’app e la parte di codice già implementata per noi. Per questo ho preferito partire da una Blank App e vedere cosa accadesse. Magari in un altro post parlerò di ciò che fanno i metodi SaveCurrentState() e RestoreLastState(). In breve, vanno a recuperare la view corrente e tramite un’interfaccia ISuspendInfo chiedono alla view le informazioni che devono essere salvate o recuperate.
I don’t know if it’s just me or if everyone else encountering issues with your site.
It looks like some of the written text in your posts are running off the screen.
Can somebody else please comment and let me know if this is happening
to them too? This might be a issue with my web browser
because I’ve had this happen previously. Thank you