Noul sistem de operare lansat de către cei de la Microsoft a adus destul de multe schimbări. Una dintre aceste schimbări este şi background tasks pentru aplicaţiile Metro.

Înainte să putem vorbi despre background task-urile din Windows 8 este nevoie să întelegem de ce au fost introduse. Windows 8 a apărut din necesitatea unui sistem de operare de a rula pe mai multe tipuri de device-uri. Pe lângă cele cu care suntem obişnuiţi din ce în ce mai multe persoane au început să folosească tabletele. Chiar dacă din punctul de vedere a procesorului şi a memoriei acestea devin din ce în ce mai puternice, aşteptările pe care le avem de la o tableta sunt diferite. Durata bateriei este extrem de importantă pentru o tabletă.

Din această cauză noul sistem de operare a celor de la Microsoft schimbă puţin lifecycle-ul pe care o aplicaţie îl are. Aplicaţiie de tip Metro sunt total diferite faţă de cele cu care ne-am obişnuit până acuma pe un sistem de operare cu Windows. Totodata conceptul de Windows Services dispare când discutăm despre o aplicaţie Metro pentru Windows 8.

Aceste aplicaţii sunt gândite să conserve cât mai mult din resursele pe care le are device-ul (procesor, memorie şi conexiune la internet şi baterie). Din această cauză doar aplicaţia care este în foreground într-un anumit moment rulează. Restul aplicaţiilor care sunt deschise dar nu sunt în foreground intră într-o stare specială numită "suspended". În cadrul acestei stări toate thread-urile sunt îngheţate, aplicaţia existând doar în memorie dar fără să execute nici un fel de cod. O aplicaţie aflată în această stare poate să revină înapoi în foreground fără nici o problemă.

img11_1.jpg

Figura 1. Lifetime-ul aplicației

Sistemul de operare poate să decidă ca o aplicaţie care este în starea "suspended" să fie oprită, iar toate resursele care sunt ocupate de aceasta să fie eliberate. Acest caz apare când sistemul nu mai are destule resurse disponibile pentru utilizator.

Nu puţine sunt aplicaţiile care au nevoie de a rula cod în background. Pentru a putea suporta această funcţionalitate Windows 8 suportă background task-ul. Acestea nu sunt chiar noi, ele existând şi pe Windows Phone 7. Conceptul de bază pentru background task din Windows 8 este destul de asemănător cu cel din Windows Phone.

Un background task reprezintă un task care rulează în fundal. Acesta nu necesită ca aplicaţia noastra să fie pornită. Momentul când acesta este pornit durata sa de viaţă este în totalitate controlată de către sistemul de operare.

În funcţie de anumite condiţii sistemul de operare poate să decidă ca background task-urile să nu ruleze pentru o periodă de timp. De exemplu dacă nivelul bateriei este mic, iar sistemul de operare doreşte să işi conserve resursele, acesta nu va mai putea să ruleze background task-urile.

img11_2.jpg

Figura 2. Procesele în care rulează task-urile de background

Există mai multe tipuri de background task-uri pe care sistemul de operare ni le pune la dispoziţie. În principiu putem să le grupăm în două tipuri principale, definite de utilizator şi cele default care vin odată cu acesta.

By default, avem câteva background task-uri definite de către Windows 8. Acestea sunt folosite pentru a executa diferite task-uri de către sistemul de operare. Totodată acestea pot fi folosite de către dezvoltatori. Se recomandă să fie folosite, deoarece nu are rost să reinventăm roata.

Mai jos gasiţi lista de background task-uri care sunt definite de sistemul de operare:

• Background audio

• Background upload

• Background download

• Sharing

• Device sync

• Live tiles

• Scheduled notifications

 

Toate aceste background task-uri sunt deja definite şi implementate de Windows 8. De exemplu pentru a putea face download la un fişier, tot ce trebuie să facem este să setăm locaţia de unde facem download şi locaţia pe disk unde să copiem fişierul. Sistemul de operare se va ocupa automat de procesul de download, iar în cazul în care conexiunea se pierde sau device-ul se restartează, Windows 8 va continua copierea fişierului automat, fără să fie necesar să facem ceva.

 

BackgroundDownloader downloader = new BackgroundDownloader();

DownloadOperation download = downloader.CreateDownload(mySource, myDestinationFile);

await download.StartAsync().AsTask();

În exemplul de mai sus am creat un background task care face download la un fişier de pe internet. Pentru fiecare task de acest tip putem să monitorizam progresul și/sau să ne creăm un cancelation token pe care îl putem folosi pentru a putea face cancel la download.

 

 

 

CancellationTokenSource cancellationToken = new CancellationTokenSource();

await download.AttachAsync().AsTask(

cancellationToken.Token,

new Progress(DownloadProgress));

Din păcate task-urile definite default de către Windows 8 nu vor ajunge pentru toate scenariile pe care ni le putem noi imagina. Pentru a veni în ajutorul nostru, Windows 8 ne permite să ne definim background task-uri custom, care se apelează automat de către sistemul de operare în funcţie de anumite evenimente.

Există nenumărate tipuri de trigger-e care ne sunt puse la dispoziţie, începând de la trigger-e care sunt apelate când avem conexiune la internet sau o nouă sesiune este creată, până la trigger-e care se apelează la un interval definit de timp. Dacă vreţi să folosiţi TimeTrigger trebuie să ţineţi cont de faptul că intervalul minim de timp este de 15 minute.

Ceea ce este foarte important de subliniat aici este faptul că un background task poate avea doar un trigger. În schimb o aplicaţie Metro poate avea oricâte background task-uri. În unele cazuri ajungem să avem task-uri care se rulează în background care au diferite dependinţe. De exemplu putem avea un backgrond task care trimite locaţia curentă a userului la un anumit interval de timp spre un server. Pentru a putea trimite datele la server avem nevoie de o conexiune la internet. Pentru a putea suporta aceste cazuri, un background task poate avea definite zero sau mai multe condiţii. Doar în momentul în care toate condiţii sunt îndeplinite acesta va fi rulat. În cazul în care una dintre condiţii nu este îndeplinită, iar după un interval de timp aceasta este îndeplinită, background task-ul o să fie rulat automat de către sistemul de operare.

Mai jos puteţi găsi lista de condiţii disponibile:

InternetAvailable

• InternetNotAvailable

• SessionConnected

• SessionDisconnected

• UserNotpresent

• UserPresent

 

Primul pas pe care trebuie să îl facă o aplicaţie Metro este să işi înregistreze trigger-ul şi clasa care o să fie apelată când se face fire pe trigger. Sistemul de operare o să apeleze automat clasa noastră. Mai jos puteti găsi flow-ul de înregistrare şi apelare a unui background task.

Codul care dorim să se execute într-un backgrond task trebuie să fie pus într-o clasa sealed care implementează interfaţa IBackgroundTask. Această interfaţă vine cu metoda Run care o să fie apelată de fiecare dată când background task-ul este apelat.

 

public sealed class MyBackgroundTask:IBackgroundTask

{

private int globalcount;

 

void IBackgroundTask.Run(IBackgroundTaskInstance taskInstance)

{

Log.WriteInfo("My Background task was called."):

}

}

În cazul unei aplicaţii Metro scrisă în C# este nevoie să ne creăm un proiect separat în care să punem această clasă. Acest lucru este necesar din cauză că acest assembly trebuie să fie încărcat de către sistemul de operare când se face fire la un trigger.

Odată ce ne-am creat un background task, acesta trebuie să fie înregistrat prin intermediul clasei BackgroundTaskBuilder.

 

BackgroundTaskBuilder taskBuilder =

new BackgroundTaskBuilder();

taskBuilder.Name = "MyBackgroundTask";

taskBuilder.TaskEntryPoint = "MyNamespace.MyBackgroundTask";

 

IBackgroundTrigger timeTrigger = new TimeTrigger(30, true);

builder.SetTrigger(timeTrigger);

IBackgroundCondition condition = new SystemCondition (SystemConditionType.InternetAvailable);

taskBuilder.AddCondition(condition);

 

IBackgroundTaskRegistration myTask = builder.Register();

În exemplul de mai sus am înregistrat background task-ul nostru că să fie apelat odata la 30 de minute doar dacă există conexiune la internet. Prin intermediul instanţei myTask putem sa ne înregistrăm la evenimentele de progress change şi de complete. În cadrul background task-ului acestea pot fi apelate prin intermediul instanţei IBackgroundTaskInstance, pe care o primim ca şi parametru în metoda Run.

 

myTask.Progress += new BackgroundTaskProgressEventHandler(TaskProgress);

myTask.Completed += new BackgroundTaskCompletedEventHandler(TaskCompleted);

Un task trebuie să fie înregistrat o singură dată, dar de fiecare dată când aplicaţia noastră este oprită şi reporneşte este nevoie să ne înregistrăm la evenimentele de Progress şi Completed.

img11_3.jpg

Figura 3. Limitările de procesare pentru un background task

img11_4.jpg

Figura 4. Constrângerile utilizării WiFi

Pentru a putea face acest lucru, în cadrul aplicaţiei putem itera prin toate background task-urile înregistrate de către aplicaţia noastră. În exemplul de mai jos, pentru fiecare background task în parte ne înregistrăm la evenimentul de Progress şi Completed.

Fiecare background task înregistrat de către aplicaţia noastră trebuie să fie declarat în fişierul de manifest. În cazul în care acesta nu este înregistrat, nu o să poată rula deloc. Pentru fiecare background task declarat în manifest este nevoie să specificăm ce tip de task-uri suportă şi entry point-ul pentru acesta.

În funcţie de trigger există background task-uri care pot fi pe lock screen. Aplicaţiile care sunt în lock screen sunt privilegiate, având acces la mai multe resurse faţă de o aplicaţie normală. Din această cauză numărul aplicaţiilor care pot fi pe acest screen este limitat.

Resursele la care are access un background task sunt limitate. Din unele puncte de vedere acestea au mai fost numite şi Windows Services din Metro style app. În comparaţie cu Windows Services, background task-urile au acces la resurse limitate. Aceste limitări au apărut din dorinţa de conservare a resurselor pe care un device le are, aici nu ne referim doar la baterie, cât şi la alte resurse precum conexiunea la internet.

img11_5.jpg

Figura 5. Înregistrarea și apelarea unui task de background

Cea mai mare limitare apare la procesor. Fiecare background task care aparţine unei aplicaţii care se află pe lock screen are dreptul la 2 CPU seconds la un interval de 15 minute. Pentru cele care nu se află în lock screen, fiecare background task are dreptul la 1 CPU second la fiecare 2 ore.

În cazul în care aveţi apeluri asyncrone spre resurse externe (de exemplu un apel spre un serviciu aflat pe un server) nu trebuie să vă faceţi griji. Înainte de acest tip de apeluri este nevoie să obţineţi o instanţă a unui obiect de tip BackgroundTaskDeferral.

 

void IBackgroundTask.Run(IBackgroundTaskInstance taskInstance)

{

BackgroundTaskDeferral deferral = taskInstance.GetDeferral();

var result = await SomeActionAsync();

deferral.Complete();

 

Log.WriteInfo("My Background task was called."):

}

 

 

public async void Run(IBackgroundTaskInstance taskInstance)

{

//

// Create the deferral by requesting it from the task instance.

//

BackgroundTaskDeferral deferral = taskInstance.GetDeferral();

//

// Call asynchronous method(s) using the await keyword.

//

var result = await ExampleMethodAsync();

//

// Once the asynchronous method(s) are done, close the deferral.

//

deferral.Complete();

}

 

Intervalul de timp în care serviciul trimite răspunsul, nu se contorizează.

Limitări asemănătoare apar şi în legătură cu accesul la reţea şi traficul maxim care se poate face la un interval de timp. Dar cea mai mare constrângere este legată de CPU.

Folosirea background task-urilor ne poate ajuta extrem de mult. Limitările pe care acestea le au sunt gândite pentru a salva cât mai multe resurse, recomandându-se ca ele să fie utlizate doar când este cu adevărat nevoie de ele.