Perché lo scorrimento/animazione di Android balbetta?
Il problema di fondo è i diversi modelli di animazione su Android e iOS. iOS utilizza CoreAnimation, un'API creata dal team iPhone per l'iPhone originale che è stata riportata sul desktop OSX. CoreAnimation è una strategia grafica in modalità retained. Anche Microsoft WP7 usa la modalità trattenuta. Google's Android usa la cosiddetta modalità grafica immediata.
Tutte le GUI funzionano generalmente allo stesso modo. C'è un thread principale con un ciclo che elabora i messaggi da una coda. I messaggi possono andare da "sposta la vista in questa posizione" o "l'utente ha eseguito un tocco nella posizione". Il punto è che si tratta di una coda, quindi ogni messaggio viene generalmente elaborato uno alla volta e in ordine di arrivo.
Per la maggior parte dei toolkit UI, compresi quelli che si trovano su iOS e Android, l'accesso e la modifica degli oggetti devono essere fatti nel thread principale. Nonostante a volte sia chiamato il thread dell'UI, di solito è anche il thread principale e spesso è responsabile non solo di dipingere, cambiare i colori, spostare gli oggetti, ma anche di caricare i file, decodificare le immagini, gestire le risposte di rete, ecc.
In Android, se si vuole animare un oggetto e fargli spostare un oggetto dalla posizione1 alla posizione2, l'API di animazione calcola le posizioni intermedie (tweening) e poi mette in coda al thread principale le operazioni di spostamento appropriate al momento opportuno utilizzando un timer. Questo funziona bene, tranne per il fatto che il thread principale è di solito usato per molte altre cose -- dipingere, aprire file, rispondere agli input dell'utente ecc. Un timer in coda può spesso essere ritardato. Programmi ben scritti cercheranno sempre di fare il maggior numero possibile di operazioni in thread in background (non principali), tuttavia non si può sempre evitare di usare il thread principale. Le operazioni che richiedono di operare su un oggetto UI devono sempre essere fatte sul thread principale. Inoltre, molte API incanalano le operazioni verso il thread principale come forma di thread-safety. Di solito è quasi impossibile mantenere tutte le operazioni sul thread principale a 1/60 di secondo per permettere alle animazioni di essere elaborate senza problemi. Anche se Google potrebbe riuscire a far sì che il suo codice faccia proprio questo, non significa che gli autori di applicazioni di terze parti saranno in grado di farlo.
In iOS anche le operazioni sugli oggetti UI devono essere fatte sul thread principale con l'eccezione delle operazioni di animazione fatte tramite CoreAnimation. CoreAnimation viene eseguito su un thread in background ed è in grado di manipolare direttamente, spostare, ricolorare e rimodellare gli oggetti UI su un thread in background (CoreAnimation). Anche il compositing e il rendering vengono eseguiti in questo thread. Lo fa attraverso una combinazione di hardware e software, fornendo animazioni molto fluide e veloci. Dal thread principale si può fondamentalmente emettere una chiamata a CallAnimation e dirgli di spostare l'oggetto1 dalla posizione1 alla posizione2. Questa animazione continuerà a funzionare anche se il thread principale è bloccato nell'esecuzione di un'altra operazione. Questo è il motivo per cui le animazioni non balbetteranno quasi mai su iOS.
Pensate al modello iOS in questo modo: Il thread principale gestisce i dati dell'applicazione e lo stato dell'applicazione UI (lo stato dell'applicazione UI include cose come le stringhe da visualizzare in una ListView ecc) ma emette richieste di cambiamento dello stato fisico dell'UI a un thread CoreAnimation separato e dedicato ad alta priorità (gli stati fisici includono cose come colore, posizione e forma). Tutti i cambiamenti di stato fisico possono essere animati e CoreAnimation eseguirà anche il tweening per voi (come le API di animazione di Android). I cambiamenti di stato fisico non animati saranno emessi direttamente da CoreAnimation e il thread principale (non quello di CoreAnimation) si bloccherà fino a quando non saranno eseguiti. I cambiamenti di stato fisico animati che sono emessi dal thread principale saranno eseguiti in modo asincrono dal thread CoreAnimation. Poiché lo stato fisico dell'UI e solo lo stato fisico dell'UI è gestito dal thread CoreAnimation, il thread principale può essere bloccato o occupato ma il thread CoreAnimation continuerà non solo a rendere accuratamente l'ultimo stato conosciuto dell'UI (come emesso dal thread principale) ma anche a continuare a rendere qualsiasi cambiamento di stato fisico dell'UI animato in sospeso o incompleto come richiesto dal thread principale.
In Windows Vista, Microsoft ha introdotto la composizione del desktop per cui il SO mantiene un pixel buffer separato per ogni finestra. Questo significa che anche se un'applicazione si blocca, l'ultimo stato della finestra (come appariva) viene ancora renderizzato piuttosto che essere semplicemente disegnato come bianco (il sistema operativo ha gestito parzialmente lo stato dei pixel nella finestra). CoreAnimation va oltre questo e scarica molto del lavoro dell'UI tradizionalmente gestito dal thread principale, compresa la gestione dello stato non solo dei pixel (come Vista) ma di concetti di livello superiore come i widget, le posizioni dei widget, i colori dei widget, ecc.
iOS e Android usano architetture software completamente diverse per eseguire le animazioni. Apple probabilmente si è concentrata di più sulla creazione di qualcosa come CoreAnimation perché Apple è molto più ossessiva riguardo al design e all'esperienza dell'utente rispetto alla maggior parte delle società di software. Sono sicuro che Steve avrebbe scambiato qualche parola con gli architetti di iOS se lo scorrimento avesse balbettato durante la lettura di un'email perché un'immagine sull'email doveva essere caricata. Gli esseri umani non sono computer. Spesso la percezione delle prestazioni è più importante delle effettive prestazioni temporali. Un'email che impiega 50ms in più per caricarsi non sarà così evidente come un touch screen che non risponde istantaneamente e si muove quando un utente ci fa scorrere sopra il dito.
Non c'è niente di troppo sbagliato nel modello di animazione di Android. È il modo in cui molti toolkit funzionano, compreso Flash, che era decisamente molto pesante in termini di animazione. Direi che il modello iOS rende l'esperienza utente complessiva più piacevole e scarica una preoccupazione in più per lo sviluppatore al sistema operativo. Sono sicuro che Google continuerà a riconoscere l'importanza dell'animazione sui dispositivi touch screen e continuerà ad accelerare (o riarchitettare) Android nelle prossime versioni.
Un iPhone di 5 anni fa di prima generazione eseguirà animazioni più fluide e affidabili dell'ultimo telefono quad core Samsung Android. Si tratta di un problema di progettazione del software e non di qualcosa in cui si possono lanciare più core (anche perché il thread principale funzionerà sempre e solo su un core!) Non credete alle persone quando giustificano la balbuzie e il lag come "oh solo il garbage collector Java di Android". I moderni garbage collector compatti e generazionali generalmente non sono la causa del tipo di stutter che vedete su Android.
Per il momento, non vedrete mai qualcosa di semplice come una ruota di caricamento stutter in iOS. Spero che questo spieghi perché :-)
Articoli simili
- Sono io o lo scorrimento sugli iPhone sembra sempre più fluido e naturale che sui telefoni Android, anche rispetto ai modelli di fascia alta?
- Qual è la velocità di scorrimento ideale per migliorare in osu!mania?
- Dove si trova il pulsante di blocco dello scorrimento su un computer portatile?
- Nintendo ha un nuovo gioco 2D a scorrimento laterale di Super Mario Bros. in sviluppo dal 2021?