Windows Phone 7 è da poche settimane disponibile sulmercato, ma il lavoro degli sviluppatori è già iniziato da alcuni mesi, quandoMicrosoft rilasciò la prima CTP dei tool. Come ormai si sa, lo sviluppo èconsentito tramite i linguaggi del .NET Framework attraverso due framework: XNAe Silverlight per Windows Phone. Quest'ultimo permette una rapidapartenza nello sviluppo di applicazioni, grazie alla diffusione che hanno ilinguaggi C# e VB e alla conoscenza della BCL, ma anche grazieall'estrema facilità degli ambienti, quali Visual Studio e Expression Blend.
Tutto questo però si scontra con i limiti che hanno idispositivi mobili, principalmente per le loro capacità contenute in termini diCPU e RAM. I requisiti minimi di un terminale sono infatti di 1GHz per laCPU e di almeno 256MB di RAM ed è quindi facile incappare inproblemi di fluidità della propria applicazione, velocità di risposta e inalcuni casi anche di stabilità, ad esempio andando in crash. In questo articolosi affrontano quindi le tematiche principali e gli errori che principalmente sipossono commettere durante lo sviluppo di un'applicazione, alcuni di naturatecnica, altri inerenti alle interfacce.
Il threading
Per affrontare in modo corretto la creazione diun'applicazione è bene conoscere prima di tutto come funziona Windows Phone 7nella gestione dell'interfaccia, delle animazioni e del proprio codice. L'entrypoint di un'applicazione è infatti il file App.xaml.cs, il qualeistanzia un PhoneApplicationFrame come contenitore principale per lanavigazione tra le pagine e utilizza l'attributo NavigationPage presentenel file WMAppManifest.xml per caricare la prima pagina visibileall'avvio dell'applicazione, istanziando la relativa classe. Le interfacce sidefiniscono infatti tramite file XAML il quale, grazie alla classe definita nelcode-behind e in particolare al metodo InitializeComponent, viene lettoper istanziare e valorizzare tutti gli elementi che compongono la UI.
Tutte queste operazioni vengono eseguite consecutivamente suunico thread, detto thread UI, il quale, terminate le operazionistartup, esegue un ciclo che mantiene in vita e processa le operazionidell'applicazione. Il thread UI, rappresentato dalla classe Dispatcher,è un elemento presente in Silverlight (per web), in WPF e in modo simile anchein tutte le applicazioni Windows, ed è responsabile della gestione degli input(riceve il touch dall'utente e scatena gli eventi), del layout, del binding,degli stili e dei template. Del thread UI e delle tematiche relative althreading se ne parla in modo approfondito in questo articolo e, sostanzialmente, in Silverlight per Windows Phone le cose non cambiano.
La regola principale è sempre la stessa: eseguire il minornumero di istruzioni sul thread UI. Questa regola è ancora più importante suWindows Phone, perché le basse capacità dei dispositivi evidenzianomaggiormente il codice scritto male. Questo problema si evidenzia soprattuttoall'avvio, quando l'applicazione impiega molto tempo per visualizzarsi. Inquesto caso i punti da controllare sono molteplici:
- il costruttore della classe che eredita da Application, in genere App;
- l'evento startup della classe Application
- il costruttore della classe iniziale che eredita da PhoneApplicationPage;
- il markup contenuto nel file XAML.
Si può evincere quindi che anche un layout particolarmentecomplesso e corposo possa influire sui tempi di startup. Il motore diSilverlight mostra infatti l'intera pagina solo al termine del ciclo completodi inizializzazione del Frame, della Page e del calcolo del layout.Semplicemente spostando del codice nell'evento Loaded si può ottenere lavisualizzazione della pagina in tempi più previ, anche se di fatto spostando ilproblema, perché il thread UI sarà poi impegnato ad eseguire quella porzione dicodice che, se impegnativa, impedirà all'utente di interagire conl'applicazione.
Come si è visto nello script #1, con lo splash screen è possibile dare subito un responso all'utente e"intrattenerlo" nell'attesa, ma ciò potrebbe non bastare dato che, sesuperati i 15 secondi, il sistema operativo provvede all'interruzionedell'esecuzione dell'applicativo. In questi casi l'alternativa è creare unosplash screen mediante una vera e propria pagina intermedia che nel frattempoprepari tutte le informazioni di cui ha bisogno.
In generale quindi i fattori da tenere in considerazionesono due: la UI e il codice. Per il primo è richiesto, come si vede poi dopoper elementi come Pivot e Panorama, una moderazione nella mole dielementi grafici che si inseriscono e richiede perciò anche una collaborazioneda parte dei grafici nella fase progettuale. Per quanto riguarda invece ilcodice, un'applicazione perfetta esegue tutte le operazioni non inerenti allaUI, in thread alternativi: del thread pool o creati appositamente.
Se si rispettano queste regole, l'applicazione già gode diottime performance, ma occorre prestare attenzione anche alle operazioni di UI.Queste vanno obbligatoriamente eseguite sul thread UI e rientrano fra esseoperazioni di binding, data template e tutto ciò che riguarda il layout. Visono situazioni in cui si esagera nella quantità di dati che si mostra o sisprecano istruzioni in valorizzazioni inutili. Scatenare l'evento PropertyChangeddell'INotifyPropertyChanged quando il valore non è cambiato, ad esempio,è uno spreco difficile anche da individuare ed è perciò necessaria una correttastesura del codice fin dalla sua nascita.
Il rendering in Windows Phone
In precedenza si è accennato alla similitudine diSilverlight del web rispetto a Windows Phone. In realtà vi è una differenzasostanziosa per quanto riguarda il rendering affidato ad un ulteriore thread,di nome compositor thread. Il suo compito è di sfruttare la GPU,supportata tramite le DirectX, per eseguire le operazioni prettamente digrafica, più precisamente:
- le trasformazioni effettuate tramite RenderTransform;
- la trasparenza gestita tramite Opacity;
- le animazioni eseguite sugli elementi;
- l'area di rendering gestita tramite Clip.
Questa precisazione è importante perché laddove la UIsfrutta questi strumenti si ottengono maggiori prestazioni grafiche e unavisualizzazione più "smooth". E' importante sottolineare però che il Clipgode di maggiore velocità se valorizzato con un RectangleGeometry,mentre le animazioni devono lavorare solo su trasformazioni, Opacity e Clip.Qualora si interviene su altre proprietà si causa l'invalidazione del layout esi richiede quindi l'intervento del thread UI.
Nell'immagine successiva si può vedere quindi come sirelazionano i thread tra di loro che possono vivere all'interno diun'applicazione.
Il thread UI si occupa quindi del binding e del layoutgrazie ad un meccanismo di invalidazione degli elementi che è possibile forzaretramite il metodo InvalidateMeasure, InvalidateArrange e UpdateLayoutpresenti su ogni elemento. Con il primo metodo si invalida lo spaziodell'elemento causandone il ricalcolo con la successiva ridisposizione; con ilsecondo si invalida solo la disposizione, mentre con il terso si forzal'esecuzione immediata dell'intero ciclo. Il meccanismo di layout diSilverlight prevede infatti una invalidazione che viene presa in considerazionesolo quando il thread UI è libero e ogni disposizione non viene immediatamenteriflettuta sul compositor thread, in modo chiamare e variare il rendering in ununico blocco, riducendo al minimo le comunicazioni con il compositor thread,permettendogli nel frattempo di continuare il suo lavoro di renderingdell'interfaccia.
E' importante quindi quando si definisce l'interfaccia,rendere il più semplice possibile il lavoro del layout system, utilizzando ilminor numero di elementi e i pannelli più adatti al risultato grafico che sivuole ottenere. Anche animazioni ed effetti si possono ottenere i differentimodi; ad esempio un elemento la cui Visibility è Collapsed toglielavoro al compositor thread, rispetto invece all'Opacity cheindipendentemente dal suo valore viene renderizzato dal motore.
Infine dall'immagine si può vedere come gli user thread sonocreati dallo sviluppatore in funzioni di eventi della UI per smaltire il lavoroper poi al termine notificare con Dispatcher.BeginInvoke.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Referenziare un @layer più alto in CSS
Esportare ed analizzare le issue di GitHub con la CLI e GraphQL
Migliorare la scalabilità delle Azure Function con il Flex Consumption
Filtrare i dati di una QuickGrid in Blazor con una drop down list
Sfruttare lo stream rendering per le pagine statiche di Blazor 8
Proteggere le risorse Azure con private link e private endpoints
Gestire domini wildcard in Azure Container Apps
C# 12: Cosa c'è di nuovo e interessante
Utilizzare i primary constructor di C# per inizializzare le proprietà
Eseguire attività basate su eventi con Azure Container Jobs
Evitare (o ridurre) il repo-jacking sulle GitHub Actions
Creare gruppi di client per Event Grid MQTT