12

Oct

Il multitasking in Mango: i background transfers

Continuiamo il nostro percorso alla scoperta delle novità di Mango e parliamo questa volta dei background transfers, ovvero una nuova funzionalità che ci permette di gestire i download e gli upload di dati all’interno della nostra applicazione anche quando questa non è in esecuzione.

Al giorno d’oggi siamo abituati ad utilizzare due classi per gestire il flusso di dati verso l’esterno: WebClient (più semplice da usare ma meno performante) e HttpWebRequest (più complessa da usare ma più completa e veloce). In Mango abbiamo a disposizione una nuova classe per questo scopo, chiamata BackgroundTransferRequest, che ha la particolarità di poter continuare a mantenere il trasferimento attivo anche ad applicazione chiusa.

E’ bene ricordare che, dato che questo tipo di trasferimento può avere un impatto sulle performance e sul consumo di batteria, sono stati introdotti dei limiti analoghi a quelli per il download di applicazioni dal Marketplace: se si è collegati ad una rete 3G, il trasferimento massimo di dati consentito è di 20 MB, che diventano 2 GB se invece siamo collegati ad una rete Wi-Fi.

Prima di approfondire l’argomento, però, dobbiamo parlare di un’altra nuova feature di Mango, molto importante nell’utilizzo dei background transfers: il mapping dell’Isolated Storage.

Un nuovo metodo di mapping dell’Isolated Storage

Nella versione attuale di Windows Phone l’unico modo per lavorare con i file memorizzati nell’Isolated Storage è utilizzare le classi messe a disposizione dal framework, come IsolatedStorageFile e IsolatedStorageFIleStream.

In Mango è stata introdotta la possibilità di esprimere i file memorizzati nell’Isolated Storage con un Uri, in questo modo:

private Uri destinationUrl = new Uri("/shared/transfers/Cocaine.mp3", UriKind.RelativeOrAbsolute);

L’esempio qui riportato è un Uri che punta al file Cocaine.mp3 memorizzato nella cartella transfers dell’Isolated Storage. Nei background transfers questo nuovo metodo di mapping è molto importante, dato che quando viene inizializzata la classe BackgroundTransferRequest è necessario specificare sia la sorgente che la destinazione proprio sotto forma di Uri. Questo perchè il download potrebbe terminare anche ad applicazione chiusa: in quel caso, se mantenessimo il file scaricato solamente in memoria non avremmo modo di gestirlo.

In realtà, questo nuovo metodo di mapping può tornare utile in tutti gli scenari in cui l’oggetto con cui si sta lavorando esponga delle proprietà che accettano un Uri come sorgente: se prima eravamo limitati a riferirci solamente a risorse incorporate nel progetto oppure esposte sul web, da oggi possiamo anche utilizzare file memorizzati nell’Isolated Storage (pensiamo ad esempio alla proprietà BackgroundImage delle tile).

Iniziamo il trasferimento

Ora che abbiamo capito come funziona il nuovo metodo di mapping, vediamo come gestire il trasferimento di dati. Innanzitutto dobbiamo definire un Uri sorgente (il file che vogliamo scaricare) e un Uri di destinazione (dove vogliamo salvare il file). Occhio che abbiamo l’obbligo di salvare tutti i file scaricati usando la classe BackgroundTransfer all’interno della cartella shared/transfers che, se non esiste, verrà creata all’occorrenza (occhio che, come raccontato in un mio post, la posizione di questa cartella è cambiata dalla beta1 alla beta2). Possiamo aggiungere altri file o altre sottocartelle all’interno di transfers, possiamo spostare il file una volta terminato il download, ma non abbiamo la possibilità di scaricare direttamente i file al di fuori di essa.

L’URL sorgente deve essere passato come parametro in fase di inizializzazione dell’oggetto, mentre l’URL di destinazione può essere passato sia come secondo parametro, sia definito in un secondo momento tramite la proprietà DownloadLocation.

Vediamo un esempio di codice, che poi commenteremo:

backgroundRequest = new BackgroundTransferRequest(sourceUrl, destinationUrl);
      backgroundRequest.Method = "GET";
      backgroundRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
      backgroundRequest.TransferProgressChanged += new EventHandler(backgroundRequest_TransferProgressChanged);
      backgroundRequest.TransferStatusChanged += new EventHandler(backgroundRequest_TransferStatusChanged);

      BackgroundTransferService.Add(backgroundRequest);

Come potete notare, la classe BackgroundRequest permette di definire le classiche impostazioni di una connessione HTTP, come il metodo (nell’esempio, POST) e gli headers. Ben più importante è sottolineare la proprietà TransferPreferences, che permette di definire le condizioni che devono essere soddisfatte affinché il trasferimento venga mantenuto in background. Le possibili opzioni sono:

  • None: è l’impostazione di default, consente il trasferimento solo se il device è in ricarica e collegato ad una rete Wi-Fi.
  • AllowBattery: consente il trasferimento solo se il device è collegato ad una rete Wi-Fi, ma è indifferente quale tipo di alimentazione si sta usando.
  • AllowCellular: consente il trasferimento solo se il device è in ricarica, ma è indifferente se sia collegato ad Internet tramite una rete Wi-Fi o tramite rete cellulare.
  • AllowCellularAndBattery: consente sempre il trasferimento, indipendente dal tipo di alimentazione e dal tipo di rete a cui è collegato.

Infine notiamo come l’oggetto ci metta a disposizione due eventi che possiamo sottoscrivere:

  • TransferProgressChanged: questo evento viene scatenato ogni qualvolta la quantità di dati trasferita cambia. Tipicamente, viene utilizzato per gestire eventuali progress bar o indicatori di altro tipo che mostrino lo stato del trasferimento.
  • TransferStatusChanged: questo evento viene scatenato nel momento in cui lo stato del trasferimento cambia. Questo tipo di informazione ci dice non solo se il trasferimento è stato completato (Completed), ma anche se ad esempio il device è in attesa di essere collegato ad una sorgente di alimentazione esterna (WaitingForExternalPower), ad una rete Wi-Fi (WaitingForWiFi) o se si trova in modalità risparmio batteria (WaitingDueToBatterySaverMode), in base alle impostazioni che abbiamo definito in precedenza.

Per dare via al trasferimento lo dobbiamo aggiungere al BackgroundTransferService che, analogamente a quanto fa lo SchedulerActionService per i task, si occupa di gestire lo scheduling dei trasferimenti in background.

Nella prossima puntata

Nel prossimo post vedremo un progetto di esempio più articolato, in cui gestiremo sia gli eventi esposti dalla classe BackgroundTransferRequest, sia il fatto che il trasferimento del file potrebbe terminare nel momento in cui la nostra applicazione è chiusa.

by Il blog di Matteo Pagani on 10/12/2012
Post archive