Ottimizzare le prestazioni delle applicazioni WinRT e XAML

di Matteo Tumiati, in WinRT 8.1,

Al giorno d'oggi, scrivere le applicazioni è diventato molto semplice. Con il supporto alle Universal App, poi, è addirittura possibile scrivere una sola volta la logica per produrre una applicazione per Windows ed una per Windows Phone.
Quello che manca davvero oggi è riuscire a scrivere le applicazioni che siano anche veloci e reattive: le applicazioni Windows e Windows Phone sono basate su terminali che hanno quantità di memoria e velocità di processori totalmente differenti e, soprattutto su uno smartphone che ha una memoria molto limitata, saper gestire le performance è importante.
In questo articolo, vedremo le principali problematiche che gli sviluppatori di applicazioni sono costretti ad affrontare ogni giorno, offrendo soluzioni più o meno semplici e più o meno 'reali' (vedremo più avanti cosa si intende), dando spazio sia a Windows che a Windows Phone.

Mantenere il thread della UI responsivo

Le Universal App basate su WinRT che usano C++, C# o Visual Basic sono applicazioni basate su eventi e tutti i componenti della UI condividono lo stesso thread di esecuzione. Basate su eventi significa che il codice viene eseguito in risposta di un evento. Dopo di che l'applicazione si mette in attesa, aspettando un nuovo evento. Visto che un thread può eseguire una sola operazione per volta, la durata di questa risulta determinante per la responsività della nostra applicazione.

Non tutti i cambiamenti della UI vengono necessariamente eseguiti sul thread della UI. C'è un thread separato dedicato alla responsività: è ad esempio, il thread che si incarica di gestire le animazioni o le transizioni.

Se il nostro codice interagisce con elementi della UI, è meglio assumere che il nostro codice potrà bloccare il thread della UI. Per questo motivo, per tenere le app responsiva, in WinRT i metodi che durano più di tre millisecondi sono asincroni così. Quando chiamiamo una API dal thread della UI, è quindi sempre consigliato usare API asincrone.

Ci sono casi in cui il tempo di esecuzione è molto più lungo del normale. In questo caso, è bene creare un nuovo thread ed eseguire il carico di lavoro in background.

Si può schedulare un lavoro asincronicamente usando l'operatore await (C#), Await (VB), o i delegates (C++), ma questo non garantisce che il lavoro verrà eseguito in un thread separato. Molte delle API del WinRT impostano il lavoro su un background thread al posto nostro, ma se lo facciamo noi dobbiamo usare Task.Run.

Nell'esempio seguente, tramite Task.Run viene eseguita la funzione ComputeNextMove che calcola la migliore mossa possibile per muovere la pedina del computer tra milioni di possibilità. E' una funzione molto onerosa dal punto di vista computazionale e temporale, quindi è bene eseguire il tutto in un background thread per non bloccare la UI.

public class Example
{
  private async void NextMove_Click(object sender, RoutedEventArgs e)
  {
    await Task.Run(() => ComputeNextMove());
    // Aggiorniamo l'UI
  }

  private async Task ComputeNextMove()
  {
    // codice con l'algoritmo
  }
}

Con l'operatore await di C#, la funzione NextMove_Click aspetterà il termine della ComputeNextMove per aggiornare la UI, sempre secondo un pattern asincrono non bloccante.

Ottimizzare il caricamento dello XAML

Il caricamento dell XAML, per quanto compilato nativamente, è una delle cose più pesanti a livello di performance. Per ogni pagina, è consigliato l'imitare la complessità del Visual Tree: se infatti abbiamo una risorsa all'interno della pagina definita in una pagina differente, il motore dello XAML deve andare ad analizzare tutta la nuova pagina in cerca della risorsa, facendo perdere del tempo prezioso che potrebbe essere speso per calcoli più complessi o tempi di avvio più rapidi.

Se si usa una risorsa all'interno di più pagine, o magari in tutta l'applicazione, allora ha senso conservare quella risorsa in un file, per accederci ovunque ed evitare duplicazioni per dichiarazioni della stessa risorsa, risparmiando ulteriormente sul tempo di parsing.

Se invece la risorsa è specifica di una sola pagina, non ha senso dichiararla all'interno di un file globale contenente molte altre risorse condivise, poiché lo XAML dovrà analizzare tutto questo file.

<Page ...>
    <Page.Resources>
        <SolidColorBrush x:Key="TextColor" Color="#FF3F42CC"/>
    </Page.Resources>
    
    <StackPanel>
        <Button Content="Submit" Foreground="{StaticResource TextColor}" />
    </StackPanel>
</Page>

Ottimizzare la composizione degli elementi

Come detto prima, il Visual Tree può essere molto complesso e lo sviluppatore può scegliere di comporre gli oggetti in una infinità di modi. Per velocizzare il render della pagina, è bene comporre appositamente la pagina, riducendo quando possibile il numero di elementi da mostrare.

  • Evitare elementi non necessari, come ad esempio, non ha senso inserire un rettangolo per aggiungere un colore di sfondo omogeneo.
        <Grid>
          <Rectangle Fill="Black" />
        </Grid>
        
    La Grid, infatti, ha già di suo la proprietà Background per svolgere lo stesso lavoro.
        <Grid Background="Black" />
        
  • Se alcuni elementi non sono visibili perché sono trasparenti o perché sono nascosti da altri elementi, è bene impostare la proprietà Visibility a Collapsed. In questo modo verranno tolti dallo stack dello XAML e non più renderizzati, rendendo il rendering più veloce.
  • Se si riutilizza lo stesso elemento più volte, magari ha senso farne una immagine. In questo caso l'immagine verrà renderizzata una sola volta e non tante volte quanti sono gli elementi, che vengono ricreati, occupando spazio nella CPU.
4 pagine in totale: 1 2 3 4
Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

Top Ten Articoli

Articoli via e-mail

Iscriviti alla nostra newsletter nuoviarticoli per ricevere via e-mail le notifiche!

In primo piano

I più letti di oggi

In evidenza

Misc