Waarom een grafsteen voor een levende applicatie?
Windows Phone 7 (WP7) biedt de gebruiker de mogelijkheid om verschillende taken parallel uit te voeren. Uiteraard moet je een inkomend gesprek kunnen opnemen, terwijl een andere applicatie actief is. Wellicht wil je een notificatie ontvangen wanneer je aandelen teveel in waarde dalen. Het executie model voor Windows Phone 7 applicaties laat het echter niet toe dat meer dan één applicatie gelijktijdig actief is. Dit werkt significant anders dan voor applicaties op andere platformen. In dit artikel lichten we toe waarom het executie model is zoals het is en hoe hier mee om te gaan, zodat een applicatie gecreëerd kan worden zoals de gebruiker verwacht. Dit wordt verhelderd aan de hand van code voorbeelden uit een eenvoudige Windows Phone applicatie.
Het executie model voor de Windows Phone 7
Het executie model regelt de hele levensduur voor applicaties op de Windows Phone vanaf het starten tot en met het afsluiten door de gebruiker. Een nieuwe applicatie kan opgestart worden uit de lijst van geïnstalleerde applicaties. Dit kan ook terwijl een andere applicatie actief is. Daarnaast kunnen applicaties ook opgestart of geactiveerd worden aan de hand van web service notificaties uit de cloud. Terwijl één of meer applicaties gestart zijn, wordt gebruik gemaakt van een navigatie model waarbij voor- en achteruit door pagina’s genavigeerd kan worden. Dit is vergelijkbaar met pagina’s in een web browser of Silverlight applicatie. De geschiedenis van pagina’s wordt hierbij bijgehouden door het operating system. Hierdoor ontstaat een consistente wijze van navigeren tussen applicaties.
Het bijzondere bij dit executie model is, dat alleen de applicatie van de huidige zichtbare pagina geladen en executeerbaar is. Alle andere applicaties zijn gestopt. Dus ook de applicaties die eerder in de navigatie geschiedenis actief waren en weer geactiveerd zouden kunnen worden door terug te bladeren. Dit laatste is onder andere mogelijk door gebruik te maken van de hardware Back knop, die standaard aanwezig is op een Windows Phone 7. Applicaties die gedeactiveerd zijn doordat een gebruiker ervandaan genavigeerd is, worden tombstoned (grafsteen) applicaties genoemd.
Er zijn twee belangrijke redenen om slechts één applicatie op deze wijze executeerbaar te laten zijn. Ten eerste zorgt dit voor een hoge responssnelheid van de actieve applicatie, omdat er geen taken in de achtergrond draaien die de snelheid nadelig beïnvloeden. Ten tweede beperkt dit zoveel mogelijk het gebruik van de beperkte resources die beschikbaar zijn op een telefoon. Overigens is het Windows Phone7 OS zelf wel een multitasking operating system, dus wanneer deze redenen in de toekomst minder relevant worden, zou het executie model kunnen wijzigen. Daarnaast is het nu al mogelijk om specifieke applicaties van de Windows Phone, zoals voor het afspelen van muziek, wel in de achtergrond te laten draaien.
Om de gebruiker de mogelijkheid te geven om taken parallel uit te voeren, worden applicaties door het operating systeem gedeactiveerd en geactiveerd. Hierbij worden events afgevuurd zodat de applicatie zijn applicatiestatus kan opslaan en inlezen. In figuur 1 is schematisch weergegeven hoe de levenscyclus van een applicatie instantie eruit ziet. Hier is te zien welke applicatiestatussen onderkend zijn en welke statusovergangen kunnen optreden.

Figuur 1 Applicatie levenscyclus voor Windows Phone 7
Starten en stoppen van een Windows Phone applicatie
Een van de manieren op de Windows Phone 7 om een applicatie te starten is vanuit een lijst van geïnstalleerde applicaties. In figuur 1 is aangegeven hoe de applicatiestatus wijzigt van gestopt naar actief (statusovergang 1). Een applicatie kan ook opnieuw gestart worden, terwijl een andere instantie van dezelfde applicatie eerder al actief is geweest (statusovergang 5). In dit geval wordt de eerdere instantie verwijderd uit de navigatie geschiedenis, omdat er van een bepaalde applicatie altijd maar één instantie tegelijk wordt toegelaten. Een applicatie stopt wanneer de gebruiker terug navigeert vanaf de eerste pagina van de applicatie (statusovergang 2).
Voor het starten en stoppen van de applicatie worden respectievelijk de Launching en Closing events afgevuurd. Bij het aanmaken van een nieuw project voor een Windows Phone 7 applicatie, wordt al automatisch code gegenereerd voor het afhandelen van deze events in de App.xaml.cs source file.
Wanneer een applicatie het Launching event ontvangt, moet de applicatie getoond worden als een nieuwe instantie van de applicatie. De Launching en Closing events handlers zijn de voor de hand liggende plek om persistente data in te lezen of op te slaan (zie Listing 1). Persistente data zijn gegevens die bewaard worden tussen verschillende instanties van de applicatie. Een voorbeeld van persistente data zijn de instellingen van de applicatie.
// Code to execute when the application is launching
// (eg, from Start)
// This code will not execute when the application
// is reactivated
private void Application_Launching(object sender,
LaunchingEventArgs e)
{
// Lege applicatie data voor nieuwe instantie.
ApplicatieData applicatieData = new ApplicatieData();
//Lees persistente data.
applicatieData.PersistenteData = laadPersistenteData();
// Gebruik data als DataContext voor de applicatie.
RootFrame.DataContext = applicatieData;
}
// Code to execute when the application is closing
// (eg, user hit Back)
// This code will not execute when the application
// is deactivated
private void Application_Closing(object sender,
ClosingEventArgs e)
{
// Schrijf persistente data.
bewaarPersistenteData((RootFrame.DataContext as
ApplicatieData).PersistenteData);
}
Listing 1 Lauching en Closing events
Voor het opslaan van persistente data wordt Isolated Storage gebruikt zoals te zien is in Listing 2.
private PersistenteData laadPersistenteData()
{
PersistenteData persistenteData = null;
using (IsolatedStorageFile isf =
IsolatedStorageFile.GetUserStoreForApplication())
{
// Probeer data van vorige instantie te laden.
if (isf.FileExists("PersistenteData.dat"))
{
using (IsolatedStorageFileStream fs =
isf.OpenFile("PersistenteData.dat",
System.IO.FileMode.Open))
{
XmlSerializer ser = new XmlSerializer(
typeof(PersistenteData));
object obj = ser.Deserialize(fs);
if (null != obj && obj is PersistenteData)
persistenteData = obj as PersistenteData;
}
}
}
return persistenteData;
}
private void bewaarPersistenteData(
PersistenteData persistenteData)
{
using (IsolatedStorageFile isf =
IsolatedStorageFile.GetUserStoreForApplication())
{
// Schrijf data naar nieuw bestand.
using (IsolatedStorageFileStream fs =
isf.CreateFile(“PersistenteData.dat”))
{
XmlSerializer ser = new XmlSerializer(
typeof(PersistenteData));
ser.Serialize(fs, persistenteData);
}
}
}
Listing 2 Lezen van en schrijven naar Isolated Storage
Executeren van meerdere pagina’s
Een gemiddelde Silverlight applicatie op WP7 zal meerderen pagina’s bevatten waartussen genavigeerd kan worden. Dit gebeurt door middel van het selecteren van UI elementen met daarachter code of door op de ‘back’ toets te drukken. Het navigeren naar een andere pagina gaat via de NavigationService.Navigate methode. Deze methode zorgt ervoor dat de navigatie geschiedenis wordt bijgehouden in het OS, ook als de applicatie tijdelijk gedeactiveerd wordt. Dit hoef je dus niet zelf bij te houden in je code.
Tijdens het navigeren gaan er verschillende events af op pagina niveau die van belang zijn m.b.t. het executie model en de state van jouw applicatie. Het Navigate_from event wordt afgevuurd als er van een pagina weg genavigeerd wordt. Dit is het moment om de tijdelijke data van de pagina te persisteren. De PhoneApplicationPage base class heeft een State dictionary beschikbaar voor het opslaan van data zoals de inhoud van UI elementen en de focus. Het Navigate_to event wordt afgevuurd, wanneer teruggekeerd wordt naar een pagina. Het is aan de applicatie om aan de hand van de PhoneApplicationPage.State dictionary de pagina te herstellen.
Activeren en deactiveren van een Windows Phone applicatie
Een Windows Phone 7 applicatie kan om verschillende redenen gedeactiveerd worden, zoals wanneer een andere applicatie gestart wordt, een telefoongesprek of SMS binnenkomt of als er een notificatie getoond wordt voor een afspraak uit de agenda (zie statusovergang 3 in Figuur 1). Wanneer de gebruiker later terugkeert naar de applicatie, wordt deze weer geactiveerd (statusovergang 4). Het kan echter ook gebeuren dat een gedeactiveerde applicatie nooit meer geactiveerd wordt, bijvoorbeeld omdat een nieuwe instantie van dezelfde applicatie wordt opgestart of omdat de telefoon wordt uitgeschakeld (statusovergang 6).
Voor het activeren en deactiveren van de applicatie worden respectievelijk de Activated en Deactivated events afgevuurd. Ook voor deze events worden in de App.xaml.cs source file automatisch code voor event handlers gegenereerd.
Wanneer de applicatie gedeactiveerd wordt, is het een goed idee om alle applicatie data inclusief vluchtige data, te bewaren. Bij het activeren van de applicatie kan deze dan weer verder draaien waar hij gebleven was. Vluchtige data is de data die op dat moment gebruikt wordt door de applicatie, maar die niet gepersisteerd wordt tussen verschillende instanties van de applicatie. Een voorbeeld van vluchtige data zijn de gegevens die ingevoerd zijn op het scherm. Daarnaast is het ook zinvol om persistente data op te slaan wanneer de applicatie gedeactiveerd wordt, omdat dus niet gegarandeerd kan worden dat de applicatie later weer geactiveerd wordt.
Voor het tijdelijk opslaan van gegevens tijdens het inactief zijn van de applicatie biedt de PhoneApplicationService class een State property waarin de huidige status van de applicatie kan worden bewaard. In Listing 3 is te zien hoe hierin de applicatie data wordt opgeslagen in de Deactivated event handler. Hierin hoeft dus niet de navigatie geschiedenis van de pagina’s binnen de applicatie bewaard te blijven, omdat dit al door het operating system geregeld wordt. Daarnaast wordt de persistente data ook gepersisteerd in Isolated Storage. De Activated event handler wordt vervolgens gebruikt om de applicatie data weer in te lezen.
// Code to execute when the application is deactivated
// (sent to background)
// This code will not execute when the application is
// closing
private void Application_Deactivated(object sender,
DeactivatedEventArgs e)
{
// Sla niet-opgeslagen data op.
PhoneApplicationService.Current.State.Add("ApplicatieData",
RootFrame.DataContext as ApplicatieData);
// Sla data ook persistent op voor het geval de
// applicatie niet meer actief wordt.
bewaarPersistenteData((RootFrame.DataContext as
ApplicatieData).PersistenteData);
}
// Code to execute when the application is activated
// (brought to foreground)
// This code will not execute when the application
// is first launched
private void Application_Activated(object sender,
ActivatedEventArgs e)
{
//Lees niet-opgeslagen data.
ApplicatieData applicatieData = null;
// Check of applicatie data als vluchtige data
// bestaat.
if (PhoneApplicationService.Current.State.ContainsKey(
"ApplicatieData"))
{
// Gevonden!
applicatieData = PhoneApplicationService.Current.State[
"ApplicatieData"] as ApplicatieData;
PhoneApplicationService.Current.State.Remove(
"ApplicatieData");
}
if (applicatieData == null)
{
// Gebruik nieuwe data voor de applicatie.
applicatieData = new ApplicatieData();
}
// Gebruik data als DataContext voor de applicatie.
RootFrame.DataContext = applicatieData;
}
Listing 3 Activated en Deactivated events
Notificaties uit de cloud
Nu zal je wel denken: “Als mijn applicatie niet actief in de achtergrond draait, en dus niet kan pollen, hoe kan ik de gebruiken dan notificeren als er voor mijn applicatie relevante gebeurtenissen optreden?”. Denk hierbij aan het notificeren van de gebruiker als je aandelen onder een bepaalde grens komen, de laatste weersverwachting of file informatie.
Voor dit soort scenario’s zijn er op het WP7 platform 3 soorten van notificatie mogelijk:
• Tile notificatie - Het actief wijzigen van een tile op het start scherm van WP7
• Toast notificatie - Een tekstueel bericht dat subtiel over het huidige scherm van de gebruiker heen getoond wordt
• Raw notificatie - Het sturen van data naar een actieve WP7 applicatie vanuit de cloud

Figuur 2 Toast en Tile op WP7
Maar als mijn WP7 applicatie deze notificaties niet initieert omdat deze inactief is, wie dan wel? Dit is waar de Microsoft Push Notificatie Services en de cloud een rol spelen.
Microsoft Push Notificatie architectuur
Het sturen van een push notificatie is een samenspel tussen drie partijen. Ten eerste het WP7 apparaat dat de notificatie ontvangt, ten tweede je eigen cloud applicatie die de notificatie initieert en als laatste de Microsoft Push Notificatie Services (MPN) die als broker tussen jouw cloud applicatie en WP7 zit.

Figuur 3 Microsoft Push Notificatie architectuur
Als een WP7 applicatie push notificatie wenst te ontvangen dan moet je eigen cloud applicatie weten waarnaar deze notificatie gestuurd moet worden. Hiervoor wordt er een kanaal geopend met de MPN Service, wat een end-point creëert op de MPN servers, en waarop jouw cloud applicatie notificaties kan posten (stap 1). De gecreëerde end-point URI wordt bij het openen van het kanaal terug gegeven en het is de verantwoordelijkheid van de WP7 applicatie om deze door te gegeven aan de cloud applicatie (stap 2). In listing 4 is het openen van een notificatie kanaal getoond. Het sturen van notificaties wordt gedaan via een HTTP POST naar deze URI in een door MPN Services afgesproken XML formaat (stap 3). Voor het versturen van een toast notificatie is in listing 5 een voorbeeld uitgewerkt. Als laatste stap (stap 4) wordt het bericht afgeleverd bij de WP7 Push Client die op de telefoon actief is.
HttpNotificationChannel channel;
void OpenNotificatieKanaal(string kanaalNaam)
{
// Controleer of het Kanaal al bestaat
channel = HttpNotificationChannel.Find(kanaalNaam);
if (null == channel)
{
channel = new HttpNotificationChannel(kanaalNaam);
// ChannelUriUpdated event wordt aangeroepen als de
// URI van PSN is verkregen na openen kanaal
channel.ChannelUriUpdated += (sender, e) =>
{
// Server heeft URI nodig voor notificatie
VerzendUriNaarCloudServer(e.ChannelUri);
};
// Open kanaal en 'wacht' op ChannelUri event
channel.Open();
}
else
{
// Uri al bekend, dan sturen naar server
if (null != channel.ChannelUri)
{
// Server heeft URI nodig voor notificatie
VerzendUriNaarCloudServer(channel.ChannelUri);
}
}
// Zorg ervoor dat de Shell de toast kan/mag tonen
if (channel.IsShellToastBound == false)
{
channel.BindToShellToast();
}
}
Listing 4 Openen notificatie kanaal
De gebruiker en afhandeling van notificaties
In WP7 staat de gebruiker centraal en is altijd in controle over wat en wanneer er iets gebeurd op de telefoon. Dit uitgangspunt wordt ook toegepast binnen de notificatie architectuur.
Als er een toast notificatie binnen komt dan wordt dit weergegeven via een melding die over de actieve UI wordt gelegd. Als de gebruiker deze notificatie selecteert dan zal de bijbehorende applicatie geactiveerd worden maar het is aan de gebruiker om dit te doen. Zo niet, dan verdwijnt de toast melding automatisch na 10 seconden. Een tile notificatie wordt door het WP7 OS zelf afgehandeld zonder dat hiervoor de client applicatie gestart hoeft te worden, omdat alle benodigde informatie in de notificatie zelf zit. Raw notificaties worden alleen doorgestuurd naar de WP7 applicatie als deze ook actief is, anders gaat deze notificatie verloren.
// Gebruik de URI die verkregen is van de PNS op WP7
// om via HTTP POST een notificatie te sturen
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(uri);
// Alleen HTTP POST is toegestaan.
request.Method = "POST";
request.ContentType = "text/xml";
request.Headers.Add("X-WindowsPhone-Target", "toast");
request.Headers.Add("X-NotificationClass", "2");
// Maak toast notificatie XML bericht aan
string toastMessage = string.Format(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\">" +
"<wp:Toast>" +
"<wp:Text1>{0}</wp:Text1>" +
"<wp:Text2>{1}</wp:Text2>" +
"</wp:Toast>" +
"</wp:Notification>", "Flits info", "A2 HMP 17.3");
using (Stream stream = request.GetRequestStream())
{
// De stream writer gebruikt standaard UTF-8
using (StreamWriter writer =
new StreamWriter(stream))
{
writer.Write(toastMessage);
}
}
// Verzend de notificatie en verkrijg response stream
HttpWebResponse response =
(HttpWebResponse)request.GetResponse();
// De response stream bevat status info
string status = response.Headers["X-NotificationStatus"];
string chStatus = response.Headers["X-SubscriptionStatus"];
string connStatus = response.Headers["X-DeviceConnectionStatus"];
Listing 5 Toast notificatie bericht sturen
Conclusies
Het Windows Phone 7 OS biedt een nieuwe en unieke wijze van applicatie levenscyclus management om een hoge responssnelheid van applicaties op de Windows Phone 7 te garanderen. Door gebruik te maken van de Windows Phone Notification Services en slechts één applicatie tegelijk actief te laten zijn, kan er zoveel mogelijk uit de beperkte resources van een telefoon gehaald worden. Tegelijkertijd moet de gebruiker in staat zijn om verschillende taken parallel uit te voeren door applicaties achter elkaar op te starten. Belangrijk hierbij is dat de applicaties in de achtergrond in het beeld van de gebruiker nog steeds draaien. Het is de taak van de ontwikkelaar om de applicatie zo te laten functioneren, dat dit inderdaad zo lijkt.