Transferencia de datos en background
- 8 minutos de lecturaDespu茅s de todas las presentaciones que el equipo de [T]echdencias hemos realizado mostrando las novedades de Windows 8, creo que no me equivocar茅 si afirmo que los temas que causan m谩s dudas y preguntas son los relacionados con el nuevo modelo de ejecuci贸n de aplicaciones y la administraci贸n del ciclo de vida de los procesos. Algo normal, por otro lado, ya que este nuevo modelo nos plantea nuevos escenarios y nos hacer cambiar la forma de desarrollar aplicaciones respecto al desarrollo cl谩sico de aplicaciones de escritorio.
Como ya expliqu茅 en un post anterior, cuando el usuario pasa una aplicaci贸n a segundo plano, el sistema la suspende a los de pocos segundos y puede, incluso, llegar a finalizarla si no hay recursos suficientes. Este comportamiento tiene dos objetivos claros: maximizar el tiempo de duraci贸n de la bater铆a y ofrecer al usuario la mejor experiencia posible, ya que no hay aplicaciones en segundo plano que interfieran y ralenticen la ejecuci贸n. Explicado as铆, esto nos plantea un entorno aparentemente muy restrictivo y en cierta manera lo es, ya que no podemos ejecutar c贸digo de nuestra aplicaci贸n si la aplicaci贸n est谩 en suspensi贸n. Afortunadamente Windows 8 nos proporciona varios mecanismos para dar la sensaci贸n al usuario de que nuestra aplicaci贸n est谩 activa incluso cuando no est谩 en ejecuci贸n, son estos:
- Reproducir audio en segundo plano mediante Playback Manager.
- Descargar y subir archivos en background mediante Background Transfer.
- Actualizaci贸n peri贸dicas de tiles.
- Notificaciones programadas y push.
Adicionalmente a estos escenarios, si la operaci贸n que queremos hacer es distinta a las anteriores, tenemos la posibilidad de ejecutar c贸digo de nuestra aplicaci贸n incluso cuando la aplicaci贸n no est谩 en ejecuci贸n a trav茅s de las tareas de background. En esta entrada y durante las siguientes de este mes vamos a ir examinando cada uno de estos escenarios, comenzando por el funcionamiento de la API para la transferencia de datos en segundo plano.
API Windows.Networking.BackgroundTransfer
Todas las clases para utilizar las funcionalidades para la transferencia de datos en segundo plano se encuentran incluidas dentro en el namespace Windows.Networking.BackgroundTransfer. Las clases principales a utilizar ser谩n BackgroundDownloader y BackgroundUploader que nos servir谩n para configurar la operaci贸n de carga y descarga. En el siguiente ejemplo iniciamos la descarga de un fichero utilizando el m茅todo createDownload al que pasamos la URI del fichero a descargar y el fichero (IStorageFile) donde se guardar谩. Este m茅todo nos devuelve un objeto *DownloadOperation **que podremos utilizar para iniciar la descarga mediante m茅todo *StartAsync.
var download = null;
var promise = null;
function downloadFile(uriString) {
var fileName = uriString.substring(uriString.lastIndexOf('/') + 1);
Windows.Storage.KnownFolders.videosLibrary.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.generateUniqueName).done(function (newFile) {
var uri = Windows.Foundation.Uri(uriString);
var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
download = downloader.createDownload(uri, newFile);
promise = download.startAsync().then(completed, failed, progress);
});
};
Un detalle importante de este c贸digo es que estamos guardando a nivel de m贸dulo tanto el objeto DownloadOperation como la promise que devuelve startAsync. Esto nos ser谩 煤til cuando queramos cancelar, pausar o reanudar la descarga.
Mostrar el progreso de transferencia
El m茅todo startAsync devuelve una promise que nos informa de cuando ha finalizado con 茅xito, cuando ha fallado y el progreso de la transferencia. En la funci贸n de progreso, podemos obtener el estado del progreso mediante la propiedad progress del objeto DownloadOperation. Entre otra informaci贸n, podemos obtener la tama帽o total de la transferencia (totalBytesToReceive) y los bytes recibidos (bytesReceived). En el ejemplo siguiente utilizamos esta informaci贸n para mostrarla mediante un control progressBar.
function progress() {
var currentProgress = download.progress;
var progressBar = document.getElementById("progressBar");
progressBar.value = currentProgress.bytesReceived;
progressBar.max = currentProgress.totalBytesToReceive;
document.getElementById("dataTransfer").innerHTML = currentProgress.bytesReceived + " bytes recibidos / " + currentProgress.totalBytesToReceive + " bytes totales";
if (currentProgress.status === Windows.Networking.BackgroundTransfer.BackgroundTransferStatus.pausedByApplication) {
displayStatus("Descarga en pausa por la aplicaci贸n.");
} else if (currentProgress.status === Windows.Networking.BackgroundTransfer.BackgroundTransferStatus.pausedCostedNetwork) {
displayStatus("Descarga en pausa debido a la directiva de costos.");
} else if (currentProgress.status === Windows.Networking.BackgroundTransfer.BackgroundTransferStatus.pausedNoNetwork) {
displayStatus("Descarga en pausa debido a una falta de conectividad.");
}
}
function completed() {
displayStatus("Descarga completada.");
}
function failed() {
displayStatus("Descarga finalizada.");
}
Pausar, reanudar y cancelar una descarga
El objeto DownloadOperation dispone de los m茅todos pause y resume que nos permiten poner en pausa y reanudar una descarga. En el ejemplo siguiente definimos las funciones para realizar estas dos acciones:
function pauseDownload () {
if (download) {
if (download.progress.status === Windows.Networking.BackgroundTransfer.BackgroundTransferStatus.running) {
download.pause();
displayStatus("Descarga pausada.");
}
else {
displayStatus("No hay ning煤na descarga activa.");
}
}
}
function resumeDownload() {
if (download) {
if (download.progress.status === Windows.Networking.BackgroundTransfer.BackgroundTransferStatus.pausedByApplication) {
download.resume();
displayStatus("Descarga reanudada.");
}
else {
displayStatus("No hay ning煤na descarga activa.");
}
}
}
Como podemos ver, antes de llamar a los m茅todos, comprobamos si tenemos una descarga activa y en progreso verificando el valor de la propiedad progress.status. Para cancelar la descarga tenemos que cancelar la promise llamando al m茅todo cancel.
function cancelDownload() {
if (promise) {
promise.cancel();
promise = null;
displayStatus("Descarga cancelada.");
}
else {
displayStatus("No hay ning煤na descarga activa.");
}
}
Recuperando informaci贸n de descarga
Cuando utilizamos la transferencia en segundo plango el sistema controla cada operaci贸n de transferencia de manera independiente y la separa de la aplicaci贸n que la lanza. As铆 que podemos cambiar de aplicaci贸n e incluso finalizarla y la transferencia continuar谩 ejecut谩ndose. Si el usuario de nuestra aplicaci贸n finaliza la aplicaci贸n y despu茅s vuelve a activarla antes de que la transferencia haya finalizado, tendremos que seguir mostrando el progreso de transferencia. Para conseguir esto, nos ayudaremos del m茅todo getCurrentDownloadAsync de la clase BackgroundDownloader que nos devuelve una colecci贸n de de descargas pendientes. Para cada una de estas descargas podremos utilizar el m茅todo attachAsync con el que nos adjuntaremos a la descarga y podremos monitorizar el progreso. En el siguiente ejemplo obtenemos la descargas activas y nos adjuntamos a la primera de la colecci贸n.
Windows.Networking.BackgroundTransfer.BackgroundDownloader.getCurrentDownloadsAsync().done(function (downloads) {
attachDownload(downloads[0]);
});
function attachDownload(loadedDownload) {
download = loadedDownload;
promise = download.attachAsync().then(completed, failed, progress);
}
Conclusiones
En esta entrada hemos visto como iniciar y gestionar la transferencia de un archivo mediante la API de BackgroundTransfer. Este tipo de transferencia est谩 pensada para ser utilizada con ficheros de gran tama帽o (video, m煤sica, etc.) y lo podemos utilizar haciendo uso de los protocolos HTTP o HTTPS y FTP para operaciones de descarga. En la siguiente entrada seguiremos explorando nuevos escenarios en los que podemos ejecutar operaciones aunque las aplicaciones no est茅n en ejecuci贸n.
Referencias
Ciclo de vida de la aplicaci贸n
Transferencia de datos en segundo plano