Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Introduzione ai background task

Link copiato negli appunti

Le applicazioni Windows Store hanno un ciclo di vita che differisce notevolmente da quello delle applicazioni "tradizionali". Anzitutto possiamo avere in esecuzione in primo piano (foreground) solo una applicazione alla volta (o al più due, in modalità "snapped"): eventuali altre app sono poste in background dal sistema.

Poi bisogna considerare che le applicazioni in background possono essere sospese o addiritutta terminate da WinRT ogni volta che il sistema necessiti di liberare risorse. Perciò, se la nostra app deve svolgere un qualche tipo di attività in background (come scaricare un file o aggiornare i tile, per esempio), servirà implementare un background task.

I background task consentono quindi alle applicazioni di compiere operazioni in background, anche in processi diversi da quello principale dell'app, e soprattutto anche quando l'applicazione stessa si trova nello stato di sospensione. Un background task consente anche di informare l'utente circa l'esito delle relative operazioni tramite un toast.

D'altro canto un background task viene eseguito in un ambiente controllato dal Windows Runtime, quindi l'accesso alle risorse di sistema sarà necessariamente limitato, come vedremo. Ecco perché i compiti di un background task dovrebbero essere non troppo complessi e evitare richieste di azioni da parte dell'utente. Inoltre meglio evitare di usare background task per eseguire logica di business o calcoli troppo complessi.

Mentre in un'applicazione in XAML/C# è possibile utilizzare un componente WinMD per creare un background task, in un'app in HTML5/JavaScript il procedimento per l'esecuzione di codice in background richiede la creazione di un nuovo file JavaScript contenente la funzione che verrà eseguita al momento opportuno. Il nome del file verrà utilizzato per identificare il relativo task.

Per prima cosa, creiamo un nuovo progetto Windows Store di tipo Blank App, come illustrato nella prossima immagine:

Figura 1.
ALT_TEXT

Aggiungiamo adesso un nuovo file JavaScript (nel nostro esempio, il file è denominato updateGPSPositionBackgroundTask.js) e includiamo il codice che verrà eseguito in background. Il prossimo snippet mostra questo punto.

(function () {
	"use strict";
	var bgTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current;
	function updateGPSPosition() {
		// Codice da eseguire in background
		close();
	}
	updateGPSPosition();
})();

La funzione sfrutta la proprietà current dell'oggetto di tipo WebUIBackgroundTaskInstance per ottenere una reference al background task, e include il metodo updateGPSPosition che rappresenta il codice che verrà eseguito in background non appena il task verrà attivato.

È importante ricordarsi di chiamare il metodo close al termine della funzione, altrimenti il background task continuerà a consumare batteria, CPU e memoria anche se il codice è stato eseguito.

A questo punto è necessario definire l'evento (denominato trigger) che scatenerà l'esecuzione del task. Quando questo evento verrà sollevato, il sistema operativo invocherà la funzione updateGPSPosition (vedremo le diverse tipologie di trigger a disposizione nel prossimo paragrafo). Per farlo, aggiungiamo le seguenti righe di codice nel file default.js:

var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
builder.name = "updateGPSPosition";
builder.taskEntryPoint = "js\\updateGPSPositionBackgroundTask.js";

Il codice è relativamente semplice: creiamo una nuova istanza della classe BackgroundTaskBuilder, che rappresenta proprio un background task pronto per essere registrato presso il sistema operativo; assegniamo un nome al nostro task e indichiamo l'entry point utilizzando il path al file JavaScript contenente il codice per il task (nel nostro caso updateGPSPositionBackgroundTask.js).

Prima di registrare il task, occorre anche definire il tipo di trigger che, una volta verificatosi, scatenerà l'esecuzione del task. In questo caso, useremo un evento di tipo MaintenanceTrigger che verrà sollevato ogni venti minuti.

var trigger = new Windows.ApplicationModel.Background.MaintenanceTrigger(20, false);
builder.setTrigger(trigger);

Infine, non resta che registrare il task presso il sistema operativo tramite il metodo Register della classe BackgroundTaskBuilder.

builder.register();

Triggers e condizioni

WinRT mette a disposizione diverse tipologie di trigger che permettono di schedulare l'esecuzione di background task a fronte di specifici eventi. I trigger sono i seguenti:

  • SystemTrigger
  • MaintenanceTrigger
  • TimeTrigger
  • PushNotificationTrigger
  • NetworkOperatorNotificationTrigger
  • NetworkOperatorHotspotAuthenticationTrigger

Alcuni di questi, come SystemTrigger e MaintenanceTrigger hanno una portata più generale, mentre gli altri hanno un campo di applicazione più limitato e specifico.

SystemTrigger

In particolare, un trigger di tipo SystemTrigger viene sollevato a fronte di specifici eventi di sistema (come ad esempio il completamento dell'aggiornamento di un'app, il cambio di fuso orario, l'aggiunta o la rimozione dell'app dal Lock screen, etc.).

Il costruttore della classe SystemTrigger accetta due parametri:

  • il primo, di tipo SystemTriggerType, rappresenta il tipo di trigger di sistema associate al background task,
  • il secondo, un Boolean denominato oneShot, indica a WinRT se avviare il task una volta soltanto (se impostato a true) ovvero ogni volta che l'evento viene sollevato.

Le seguenti righe di codice mostrano come utilizzare la classe SystemTrigger per definire un background task che verrà eseguito ogni volta che la connessione a internet torna a essere disponibile.

var systemTrigger = new Windows.ApplicationModel.Background.SystemTrigger(Windows.ApplicationModel.Background.SystemTriggerType.internetAvailable, false);
builder.setTrigger(systemTrigger);

L'enumerazione completa dell'enum SystemTriggerType è la seguente:

Tipo di trigger Descrizione
Invalid non rappresenta un tipo di trigger valido
SmsReceived viene sollevato quando un nuovo SMS è ricevuto dal device mobile
UserPresent viene sollevato quando l'utente torna presente, ossia quando sblocca il Lock screen. Perché questo trigger possa funzionare è necessario che l'app sia aggiunta al Lock screen
UserAway viene sollevato quando l'utente è assente ed entra in funzione il Lock screen. Anche in questo caso è necessario che l'app sia aggiunta al Lock screen perché il background task possa essere effettivamente registrato
NetworkStateChange viene sollevato quando si verifica un cambiamento nella connessione o nei relativi costi
ControlChannelReset viene sollevato quando il control channel viene resettato. È necessario che l'app sia aggiunta al Lock screen perché il background task possa essere effettivamente registrato
InternetAvailable viene sollevato quando la connessione a internet diviene disponibile
SessionConnected viene sollevato quando la sessione è connessa. È necessario che l'app sia aggiunta al Lock screen perché il background task possa essere effettivamente registrato
ServicingComplete viene sollevato quando il sistema operativo ha terminato l'aggiornamento di un'app
LockScreenApplicationAdded viene sollevato quando un'app viene aggiunta al Lock screen
LockScreenApplicationRemoved viene sollevato quando un'app viene rimossa dal Lock screen
TimeZoneChange viene sollevato quando la "time zone" del device viene modificata e nel caso in cui la nuova zona preveda una modifica di fuso orario che comporti una modifica all'ora di sistema.
OnlineIdConnectedStateChange viene sollevato quando l'account Windows Live viene modificato
BackgroundWorkCostChange viene sollevato quando il costo dell'operazione in background si modifica. È necessario aggiungere l'applicazione al Lock Screen affinché questo evento possa essere registrato

MaintenanceTrigger

L'altro trigger di carattere generale è quello di tipo MaintenanceTrigger, che può essere utilizzato per schedulare operazioni periodiche da eseguire in background. In questo senso, svolge funzioni analoghe al TimeTrigger, con la differenza che quest'ultimo viene sollevato solo se l'utente ha aggiunto l'app al Lock screen.

Un'altra importante differenza è che le attività in background che utilizzano un MaintenaceTrigger vengono eseguite solo quando il device è collegato all'alimentazione (in caso contrario i relativi eventi non vengono sollevati).

Tanto il costruttore della classe MaintenanceTrigger, quanto quello della TimeTrigger accettano gli stessi due parametri:

  • il primo, denominato freshnessTime, specifica il numero di minuti che devono trascorrere prima che il background task venga eseguito;
  • il secondo, oneShot, è un Boolean che indica se il trigger deve essere sollevato solo una volta ovvero a intervalli di tempo regolari.

Ad esempio, tramite il seguente codice il background task verrà schedulato per essere eseguito ogni sessanta minuti.

builder.setTrigger(new Windows.ApplicationModel.Background.MaintenanceTrigger(60, false));

È importante ricordare che WinRT ha un timer interno che esegue i task schedulati ogni 15 minuti.

Questo significa che se freshnessTime viene impostato a 15 minuti e oneShot a false, il task parte alla prossima occorrenza del timer interno (al massimo entro 15 minuti) e viene eseguito ogni 15 minuti. Se il task invece viene registrato con il parametro oneShot a true, il task viene eseguito una sola volta nei 15 minuti dal momento della registrazione.

Vuol dire anche che non è possibile impostare il freshnessTime a un valore inferiore a 15 minuti. In caso contrario, otterremmo un'eccezione, come mostrato nella prossima immagine:

Figura 2.

Altri trigger

WinRT espone anche altri tipi di trigger specifici:

  • il PushNotificationTrigger, che viene sollevato quando arriva una notifica tramite il Windows Push Notifications Service channel;
  • il trigger NetworkOperatorNotificationTrigger, legato alla notifica di un operatore di rete mobile;
  • il NetworkOperatorHotspotAuthenticationTrigger, che rappresenta un trigger di autenticazione dell'hotspot dell'operatore di rete mobile.

Le API di Windows 8.1 hanno infine aggiunto un ulteriore tipologia di trigger, rappresentata dalla classe LocationTrigger, che permette di eseguire background task in base alla posizione geografica dell'utente (geofencing).

Condizioni

È anche possibile definire condizioni che devono essere verificate dal sistema operativo prima di avviare un determinate background task. La classe BackgroundTaskBuilder espone infatti il metodo AddCondition, il quale permette di aggiungere una singola condizione alla volta, sotto forma di un oggetto di tipo SystemCondition.

builder.addCondition(new Windows.ApplicationModel.Background.SystemCondition(Windows.ApplicationModel.Background.SystemConditionType.internetAvailable));

Il costruttore della classe SystemCondition accetta infatti una istanza di tipo SystemConditionType, che enumera le possibili condizioni cui può essere subordinata l'esecuzione di un background task. L'enumerazione include le seguenti possibilità:

Condizione Descrizione
Invalid Non è una condizione valida.
UserPresent il background task può essere eseguito solo se l'utente è presente. Se il trigger viene sollevato durante l'assenza dell'utente, il relativo background task verrà eseguito non appena l'utente tornerà presente.
UserNotPresent il background task può essere eseguito solo se l'utente non è presente. Se il trigger viene sollevato quando l'utente è presente, il relativo background task verrà eseguito non appena l'utente non sta più usando l'applicazione.
InternetAvailable il background task viene eseguito solo se è presente l'accesso a internet. Se il trigger viene sollevato in assenza di una connessione a internet, il relativo background task verrà eseguito non la connessione tornerà disponibile.
InternetNotAvailable il background task viene eseguito solo se manca l'accesso a internet. Se il trigger viene sollevato in presenza di una connessione internet, il relativo background task verrà eseguito non appena la connessione non sarà più disponibile.
SessionConnected il background task viene eseguito solo se la sessione utente è connessa. Se il trigger viene sollevato quando l'utente non ha ancora effettuato il login, il relativo background task verrà eseguito non appena l'utente effettuerà l'accesso.
SessionDisconnected il background task viene eseguito solo se l'utente ha effettuato il logout. Se il trigger viene sollevato quando l'utente è ancora loggato, il relativo background task verrà eseguito non appena l'utente effettuerà il logout.
FreeNetworkAvailable il background task viene eseguito solo quando è disponibile una connessione di rete gratuita.
BackgroundWorkCostNotHigh il background task verrà eseguito solo se il relativo carico di lavoro è basso.

Il seguente snippet mostra come subordinare l'esecuzione di un background task al verificarsi di due condizioni:

builder.addCondition(new Windows.ApplicationModel.Background.SystemCondition(Windows.ApplicationModel.Background.SystemConditionType.internetAvailable));
builder.addCondition(new Windows.ApplicationModel.Background.SystemCondition(Windows.ApplicationModel.Background.SystemConditionType.sessionConnected));

Dichiarare il background task nell'application manifest

Affinché la registrazione di un background task sia possibile, è necessario dichiarare la relativa capacità nell'application manifest, indicando anche il tipo di trigger che scatenerà l'evento. La prossima immagine mostra il manifest con la dichiarazione del background task e del relativo trigger.

Figura 3.

Nel manifest di un'applicazione Windows Store in JavaScript, come Start page deve essere indicato il path al file JavaScript che contiene il codice da eseguire in background. Anche se il manifest indica una "page", se provassimo a indicare una pagina HTML o CSS otterremmo un errore: un background task non è nient'altro che un web worker, per cui non richiede nessuna UI. Per notificare informazioni all'utente possiamo utilizzare toast, tile e badge.

Aprendo il manifest con l'editor XML, si nota che Visual Studio ha aggiunto un'apposita sezione con l'indicazione della Start page del background task e del tipo di task (systemEvent).

<Extensions>
	<Extension Category="windows.backgroundTasks"
			   StartPage="js\updateGPSPositionBackgroundTask.js">
		<BackgroundTasks>
			<Task Type="systemEvent" />
		</BackgroundTasks>
	</Extension>
</Extensions>

C'è da tener presente che se il tipo di trigger richiede l'interazione con il Lock screen (es. PushNotificationTrigger, TimeTrigger, ecc.), nell'application manifest, bisognerà anche specificare il modo con cui l'app mostrerà le notifiche sul Lock screen e fornire l'immagine da utilizzare per il badge.

Figura 4.

Enumerare i task registrati

Quando si registra un background task, è importante essere sicuri di farlo una sola volta, altrimenti potremmo vedere lo stesso task eseguito più volte. Per testare se un task è già stato registrato, possiamo usare la classe BackgroundTaskRegistration e verificare la proprietà Value.Name come mostrato nel seguente snippet:

var taskName = "updateGPSPosition";
var taskRegistered = false;
var taskEntryPoint = "js\\updateGPSPositionBackgroundTask.js";
var iter = Windows.ApplicationModel.Background.BackgroundTaskRegistration.allTasks.first();
while (iter.hasCurrent) {
	var task = iter.current.value;
	if (task.name === taskName) {
		taskRegistered = true;
		break;
	}
	iter.moveNext();
}
var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
builder.name = taskName;
builder.taskEntryPoint = taskEntryPoint;
builder.setTrigger(new Windows.ApplicationModel.Background.MaintenanceTrigger(20, false));
builder.addCondition(new Windows.ApplicationModel.Background.SystemCondition(Windows.ApplicationModel.Background.SystemConditionType.internetAvailable));
builder.addCondition(new Windows.ApplicationModel.Background.SystemCondition(Windows.ApplicationModel.Background.SystemConditionType.sessionConnected));
builder.register();

Il codice esegue un loop sui background task registrati dall'applicazione sfruttando il relativo dictionary esposto tramite la proprietà AllTasks dell'oggetto di tipo BackgroundTaskRegistration. Quindi il codice procede a registrare il task corrente, ma solo nel caso in cui un task con lo stesso nome non sia stato già registrato presso il sistema operativo, evitando così di eseguire più volte lo stesso codice in background.

Eseguire codice asincrono in un background task

Se il codice da eseguire in background è asincrono, il relativo task dovrà utilizzare un deferral (la stessa tecnica utilizzata per gestire la sospensione dell'applicazione). Per ottenere un deferral, utilizziamo il metodo GetDeferral esposto dall'oggetto di tipo WebUIBackgroundTaskInstance che rappresenta il background task corrente.

(function () {
	"use strict";
	var bgTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current;
	function updateGPSPosition() {
		var deferral = bgTaskInstance.getDeferral();
		// codice da eseguire in background
		deferral.complete();
		close();
	}
	updateGPSPosition();
})();

Dopo aver richiesto una reference al deferral, possiamo utilizzare il pattern asincrono per eseguire del codice in background e, al termine delle relative operazioni, invocare il metodo Complete sul deferral per segnalare al sistema che l'operazione è conclusa. È importante ricordarsi di eseguire tutto il codice tra la richiesta del deferral e la chiamata al metodo Complete, altrimenti il sistema assumerà che l'operazione è stata completata e che il thread può essere distrutto.

Nelle prossime lezioni esamineremo con esempi pratici alcune casistiche legate ai background task.

Ti consigliamo anche