In questa sezione della guida approfondiamo gli aspetti legati al ciclo di vita (Application Lifecycle Management, o più brevemente ALM) di un'applicazione Windows Store. In particolare, in questa lezione analizziamo il processo di attivazione di un'applicazione da parte di Windows RT, mentre nelle prossime approfondiremo gli aspetti legati alla sospensione, alla chiusura e al ripristino di un'applicazione Windows Store.
Come di consueto l'approccio è pratico, cominciamo subito quindi con l'aprire Visual Studio 2012 e creare un nuovo progetto di tipo Windows Store e selezioniamo Blank App (XAML) come template da cui partire. Date alla solution il nome che preferite (nel nostro caso Html.it.Demo.Windows8.ALM
), scegliete la directory su filesystem e premete OK.
Se ora diamo un'occhiata alla solution creata da Visual Studio 2012, troviamo che nel nostro progetto è presente un file App.xaml.cs
, che contiene la definizione della classe App
che deriva dalla classe base Application offerta dal Windows Runtime. Questa classe rappresenta la nostra applicazione e i relativi servizi e permette di ridefinire (mediante override) una serie di comportamenti specifici della nostra applicazione come, ad esempio, le operazioni da compiere in fase di attivazione (OnLaunched
) e sospensione (OnSuspending
) dell'applicazione stessa.
In particolare, il metodo OnLaunched è invocato da Windows RT quando l'applicazione viene lanciata dall'utente cliccando sulla relativa tile. Quella che segue è l'implementazione di default del metodo OnLaunched
proposto dai template di Visual Studio:
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
// Ensure the current window is active
Window.Current.Activate();
}
Come si vede, il metodo riceve come parametro un argomento denominato args di tipo LaunchActivatedEventArgs
. Questa classe implementa l'interfaccia IActivatedEventArgs
ed espone due proprietà particolarmente utili per la gestione del ciclo di vita di un'applicazione:
- Kind
- PreviousExecutionState
La prima, di tipo ActivationKind, è definita dall' enum che consente di determinare il tipo di attivazione dell'istanza. Ad esempio, se l'applicazione è stata lanciata dall'utente, essa sarà di tipo ActivationKind.Launch; se invece è stata attivata dal runtime come reazione a una richiesta di sharing, sarà di tipo ActivationKind.ShareTarget, e così via. L'elenco completo è riportato qui di seguito:
// Summary:
// Specifies the type of activation.
[Version(100794368)]
public enum ActivationKind
{
// Summary:
// The user launched the app or tapped a content tile.
Launch = 0,
//
// Summary:
// The user wants to search with the app.
Search = 1,
//
// Summary:
// The app is activated as a target for share operations.
ShareTarget = 2,
//
// Summary:
// An app launched a file whose file type this app is registered to handle.
File = 3,
//
// Summary:
// An app launched a URL whose protocol this app is registered to handle.
Protocol = 4,
//
// Summary:
// The user wants to pick files or folders that are provided by the app.
FileOpenPicker = 5,
//
// Summary:
// The user wants to save a file and selected the app as the location.
FileSavePicker = 6,
//
// Summary:
// The user wants to save a file that the app provides content management for.
CachedFileUpdater = 7,
//
// Summary:
// The user wants to pick contacts.
ContactPicker = 8,
//
// Summary:
// The app handles AutoPlay.
Device = 9,
//
// Summary:
// The app handles print tasks.
PrintTaskSettings = 10,
//
// Summary:
// The app captures photos or video from an attached camera.
CameraSettings = 11,
}
Dal momento che il metodo OnLaunched
è invocato dal sistema operativo a seguito del click dell'utente sul tile della nostra applicazione, non è normalmente necessario procedere a verificare il tipo di attivazione. In C# e VB, infatti, nel caso in cui l'applicazione sia stata lanciata da Windows RT per rispondere alla richiesta di Search o di Share dal parte dell'utente, verranno invocati eventi specifici: vi rimandiamo negli articoli di questa guida relativi a Search e Share.
Il discorso cambia nel caso di applicazioni Windows Store scritte in HTML/Javascript, perché in questo caso il punto di ingresso è unico per qualunque tipo di attivazione, per cui è fondamentale determinare come e perché la nostra applicazione è stata lanciata, così da poter rispondere nel modo più appropriato.
La proprietà PreviousExecutionState, di tipo ApplicationExecutionState
, è sempre un enum, e consente di determinare lo stato dell'esecuzione precedente dell'applicazione: ad esempio, se l'applicazione è stata chiusa dall'utente (ClosedByUser
), oppure se è stata terminata dal runtime (Terminated
).
L'enumerazione è riportata qui di seguito:
// Summary:
// Specifies the execution state of the app.
[Version(100794368)]
public enum ApplicationExecutionState
{
// Summary:
// The app is not running.
NotRunning = 0,
//
// Summary:
// The app is running.
Running = 1,
//
// Summary:
// The app is suspended.
Suspended = 2,
//
// Summary:
// The app was terminated after being suspended.
Terminated = 3,
//
// Summary:
// The app was closed by the user.
ClosedByUser = 4,
}
Il resto del metodo OnLaunched si limita sostanzialmente a creare un nuovo oggetto Frame (rootFrame), impostandolo come contenuto corrente (Window.Current.Content = rootFrame), e a invocare il metodo Navigate della classe Frame passando come parametro la pagina proposta per default (MainPage), la quale viene infine attivata tramite l'invocazione del metodo Window.Current.Activate.
Premesso che torneremo nuovamente sul codice sopra riportato, proviamo a modificare il metodo OnLaunched aggiungendo, giusto all'inizio del metodo, le due linee di codice nel seguente listato:
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
// righe da aggiungere
var dia = new Windows.UI.Popups.MessageDialog("È stato invocato il metodo OnLaunched", "DevLeap ALM Demo");
dia.ShowAsync();
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
(resto del codice omesso per brevità)
Le linee aggiunte al corpo del metodo non fanno niente di particolare, se non mostrare un MessageDialog con un testo d'esempio nel momento in cui l'applicazione viene attivata. Il risultato è mostrato nella prossima immagine:
Tenete presente che non è possibile attivare più istanze di una applicazione Windows Store: in pratica può esistere una sola e unica istanza in esecuzione (cosa che rappresenta una significativa differenza rispetto alle precedenti versioni di Windows). Infatti, se l'utente lascia la nostra applicazione per tornare alla Start Page (premendo il tasto Windows) e poi preme nuovamente sul tile dell'applicazione, Windows RT si limiterà a ripristinare quest'ultima in foreground senza attivare una nuova instanza come avveniva per le precedenti versioni di Windows e come avviene ancora per le applicazione Desktop.
Proviamo adesso a "giocare" un po' con ciascuna di queste proprietà per comprenderne meglio il funzionamento.
Sostituiamo le righe di codice aggiunte in precedenza con le seguenti (già che ci siamo, semplifichiamo anche un po' il testo originale):
String message = String.Format("Metodo invocato: OnLaunched - ActivationKind : {0}", args.Kind.ToString());
var dia = new Windows.UI.Popups.MessageDialog(message, "DevLeap ALM Demo");
dia.ShowAsync();
Il risultato è mostrato nella seguente immagine:
Se ActivationKind
definisce il tipo di attivazione dell'applicazione, la proprietà PreviousExecutionState
ci informa invece sullo stato della precedente esecuzione della stessa. Ad esempio, se l'utente ha regolarmente chiuso l'applicazione premendo ALT+F4
(ovvero trascinando la finestra dell'applicazione verso il basso), se lanciamo nuovamente l'applicazione lo stato precedente risulterà essere ClosedByUser
; al contrario, se l'applicazione era stata semplicemente sospesa dal runtime e viene ripristinata, lo stato sarà Suspended, e così via.
Per meglio comprendere questo punto, sostituiamo nuovamente le linee di codice aggiunte in precedenza con le seguenti:
String message = String.Format("ActivationKind : {0} - Previous State: {1}", args.Kind.ToString(), args.PreviousExecutionState.ToString());
var dia = new Windows.UI.Popups.MessageDialog(message, "DevLeap ALM Demo");
dia.ShowAsync();
Se ora effettuate il deployment dell'applicazione e la lanciate, dovreste ottenere qualcosa del genere:
Lo stato di NotRunning
indica che l'applicazione non era ancora stata lanciata: abbiamo infatti appena effettuato il deployment.
Se chiudete l'applicazione premendo ALT+F4, lasciate passare qualche secondo per dare modo al runtime di chiudere effettivamente l'applicazione, e la rilanciate, il risultato dovrebbe essere diverso:
Windows RT si comporta in modo decisamente diverso rispetto a Windows "desktop", consentendo l'attivazione di una sola istanza per ogni applicazione Windows Store. La classe Application ci consete di intercettare gli eventi di lancio dell'applicazione da parte dell'utente, di lancio per ricerca dal Search Pane e così via.
I parametri che questi metodi ricevono consentono inoltre di capire lo stato in cui l'applicazione si trovava prima del lancio: ad esempio è possibile sapere se l'applicazione era appena stata installata oppure era già stata lanciata dall'utente o ancora se era stata chiusa precedentemente.
Nelle prossime lezioni esamineremo la sospensione e la terminazione di una applicazione da parte del sistema operativo.