Multitasking è la caratteristica di un sistema operativo in grado di eseguire diversi programmi contemporaneamente; l'implementazione di tale funzionalità in un dispositivo mobile però aggiunge un'importantissima variabile: il consumo di batteria.
L'obiettivo del multitasking in Windows Phone è infatti di allargare le possibilità in termini di funzionalità di un'applicazione pur ottimizzando il consumo di risorse hardware.
Windows Phone consente a una sola applicazione alla volta di girare in foreground, ma possiamo sfruttare tutta una serie di funzionalità di multitasking per consentire all'applicazione di eseguire attività anche quando non sarà più l'app in foreground.
Windows Phone 7.5 suddivide in cinque aree diverse il concetto di multitasking.
1. Scheduled Task
Gli Scheduled Task sono degli "agent" in grado di eseguire del codice in background, esistono due tipologie di background agent: PeriodicTask
e ResourceIntensiveTask
.
PeriodicTask rappresenta un agent periodico, ovvero una breve esecuzione di codice a intervalli regolari, tipici esempi sono la sincronizzazione di dati o l'upload della posizione gps, viene eseguito ogni 30 minuti dal sistema operativo e potrà girare per un massimo di 25 secondi.
ResourceIntensiveTask è un agent in grado di eseguire del codice per un periodo di tempo più lungo ma necessita di specifici requisiti di alimentazione e rete per poter essere lanciato, un esempio è rappresentato dalla sincronizzazione di grandi moli di dati (ricordiamo comunque che il termine "grande" è sempre rapportato alle caratteristiche di un device mobile).
Questo agent, per poter essere lanciato dal sistema operativo, necessita che il device sia collegato al suo alimentatore esterno, sia presente connettivà Wi-Fi o tramite un PC, che la batteria sia maggiore del 90%, così sarà in grado di elaborare codice per un massimo di 10 minuti.
Un agent è implementato in una classe derivata da BackgroundAgent, al momento dell'esecuzione verrà chiamato il metodo OnInvoke, all'interno di tale metodo dovremmo implementare la logica del nostro task.
Al termine delle nostre operazioni dovremmo chiamare il metodo NotifyComplete o Abort per notificare il sistema operativo, come è logico immaginare NotifyComplete
equivale a una conclusione positiva del nostro lavoro, mentre Abort
rappresenta l'impossibilità a concludere il task, in tal caso la proprietà IsScheduled verrà automaticamente impostata a false, un'applicazione in foreground potrà usare tale proprietà per determinare se il task in background è stato eventualmente abortito.
Per creare un background agent dobbiamo, da una solution contenente un'applicazione tradizionale Windows Phone 7.5, aggiungere un nuovo progetto di tipo Windows Phone Scheduled Task Agent e referenziarlo dall'applicazione di user interface. Visual Studio creerà l'infrastruttura necessaria per il compito: una classe derivata da ScheduledTask con i metodi di gestione eccezioni (ScheduledAgent_UnhandledException
) e il fondamentale override di OnInvoke
:
protected override void OnInvoke(ScheduledTask task)
{
ShellToast toast = new ShellToast();
toast.Title = "shopping online";
toast.Content = "c'è un nuovo prodotto di tuo interesse";
toast.NavigationUri = new Uri("/NuoviProdotti.xaml", UriKind.Relative);
toast.Show();
NotifyComplete();
}
In questo semplice esempio informiamo l'utente della presenza di nuovi prodotti tramite le API di ShellToast: un classico popup informativo, notare la proprietà NavigationUri
che consentirà automaticamente di navigare verso una pagina interna dell'applicazione quando l'utente toccherà il popup.
Notiamo inoltre che l'operazione di "Add Reference" di un progetto Scheduled Task, oltre alle classiche attività, modificherà anche il file WMAppManifest.xaml aggiungendo il seguente frammento xml:
<ExtendedTask Name="BackgroundTask">
<BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="ScheduledTaskAgent1"
Source="ScheduledTaskAgent1" Type="ScheduledTaskAgent1.ScheduledAgent" />
</ExtendedTask>
Dall'applicazione di foreground è sufficiente il seguente codice per attivare il nostro agent:
PeriodicTask task = new PeriodicTask("ScheduledTaskAgent1");
task.Description = "background agent di esempio";
ScheduledActionService.Add(task);
Dopo questa operazione il nostro agent verrà lanciato dal sistema operativo ogni 30 minuti.
Durante lo sviluppo è comodo usare il metodo statico ScheduledActionService.LaunchForTest per lanciare l'esecuzione dell'agent con un intervallo di tempo minore rispetto ai tradizionali 30 minuti, ad esempio:
ScheduledActionService.LaunchForTest("ScheduledTaskAgent1", TimeSpan.FromSeconds(60));
Il precedente codice permette infatti di far rieseguire il nostro agent ogni minuto.
2. Background File Transfer
Il servizio di Background Tranfer consente a un'applicazione di accodare diverse richieste di trasferimento file via http che continueranno il loro lavoro anche quando l'applicazione non sarà più in foreground. Sono supportate le operazioni di download e upload. Tratteremo più a dondo questo tema più avanti nella guida.
3. Scheduled Notification
Questa caratteristica permette a un'applicazione Windows Phone di registrare "sveglie" e reminder singoli o ricorrenti che verranno mostrati con una user interface identica ai popup dei reminder dell'applicazione interna del calendario. Tali dialog box visualizzeranno del testo personalizzabile e due pulsanti per consentire all'utente di postporre la notifica o annullarla; al touch della dialog verrà lanciata la nostra applicazione.
Esistono due tipologie di scheduled notification: Alarm e Reminder. La classe Alarm permette di specificare un file sonoro da riprodurre quando la notifica verrà lanciata, mentre se usiamo un Reminder saremo in grado di specificare un "querystring" che verrà passato alla nostra applicazione quando l'utente toccherà il popup.
Nel prossimo esempio definiamo nell'evento di click di una tradizionale app il codice per inizializzare un'istanza di Alarm.
Alarm alarm = new Alarm("HTML.IT");
alarm.BeginTime = DateTime.Now.AddMinutes(5);
alarm.Content = "Spaghetti!";
alarm.RecurrenceType = RecurrenceInterval.None;
ScheduledActionService.Add(alarm);
Il codice è decisamente autoesplicativo, è sufficiente impostare BeginTime
, il tipo di RecurrenceType
(nel nostro caso desideriamo una notifica singola e non ricorrente) e Content
(verrà mostrato nella UI della dialog di notifica), ricordiamo inoltre di aggiungere la nostra "sveglia" alla collezione di elementi del servizio di notifica. Dopo 5 minuti verrà mostrata all'utente la seguente user interface, al touch del box (qualsiasi zona ad esclusione ovviamente dei due pulsanti) verrà lanciata la nostra app.
Possiamo anche impostare la proprietà Sound per specificare una traccia audio da riprodurre alla scadenza.
alarm.Sound = new Uri("/Suoneria01.wma", UriKind.Relative);
Creare un'instanza di Reminder è analogamente semplice:
Reminder reminder = new Reminder("HTML.IT");
reminder.BeginTime = DateTime.Now.AddDays(1);
reminder.Title = "Piscina";
reminder.Content = "Corso Sub";
reminder.RecurrenceType = RecurrenceInterval.Weekly;
reminder.NavigationUri = new Uri("/MainPage.xaml?tipo=sub", UriKind.Relative);
ScheduledActionService.Add(reminder);
La classe Reminder
ha l'utile proprietà NavigationUri, che consente di impostare un uri compreso di querystring che verrà passato alla nostra applicazione quando l'utente premerà la dialog. Nel nostro esempio il device ritornerà alla "home page" aggiungendo un parametro chiamato "tipo". Per rileggere tale parametro è sufficiente eseguire l'override del metodo OnNavigatedTo:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string parameter;
NavigationContext.QueryString.TryGetValue("tipo", out parameter);
TypeTextBlock.Text = parameter;
}
4. Fast Application Switching
In Windows Phone 7.0 ogni applicazione non attiva diventava tombstoned: il suo stato veniva serializzato e memorizzato nell'isolated storage dell'app e l'applicazione viene terminata e quindi scaricata dalla memoria; quando l'utente ritornava su un'applicazione in stato di tombstoned doveva attendere la deserializzazione dello stato e il ripristino per procedere all'utilizzo.
Se da un punto di vista del consumo di risorse hardware e software è una scelta sicuramente sensata, per l'utente finale però dovere attendere i continui "resuming..." fra un back e l'altro non è il massimo della user experience.
In Windows Phone 7.5 quando un'applicazione è messa in background raggiunge la stato di dormant: il sistema operativo mantiene la sua immagine viva in memoria per quanto più possibile senza influenzare le prestazioni generali del sistema, quando l'utente navigherà di nuovo verso l'applicazione il recupero sarà virtualmente istantaneo. È importante evidenziare che il sistema operativo potrà ancora terminare un'applicazione se necessita di memoria per le nuove app.
Per abilitare il Fast Application Switching non dobbiamo implementare nessuna tipologia di operazione programmatica, ma possiamo interrogare la proprietà IsApplicationInstancePreserved di ActivatedEventArgs dell'evento Activated per capire se l'attivazione dell'applicazione proveniva da uno stato dormant o tombstoned, nel primo caso infatti non dobbiamo deserializzare nessuna risorsa considerato che il processo non è stato terminato.
private void Application_Activated(object sender, ActivatedEventArgs e)
{
if (e.IsApplicationInstancePreserved)
{
//stato di dormant: il processo è ancora attivo
}
else
{
//stato di tombstoned
}
}
5. Background Audio
Questa caratteristica permette a un'applicazione Windows Phone di riprodurre tracce audio anche quando l'app non è più in foreground. Nella lezione "Gestire l'audio del telefono" ampliamo la trattazione del tema.