Come accennato nel precedente articolo, uno dei più grossi problemi di cui soffre Android è quello della frammentazione, argomento questo che meritava di essere approfondito, in particolare dal punto di vista tecnico.
Senza entrare troppo nei dettagli, una buona base di partenza per comprendere il concetto è rappresentata dalla finestra che si apre quando si decide di creare (o modificare) una nuova macchina virtuale (Android Virtual Device, abbreviato con AVD) sulla quale far girare il nostro codice:
All’apparenza non ci sono molte voci, ma le tre più importanti (Target, Skin, e Hardware) sono sufficienti a complicarci la vita, presentando numerose opzioni / possibilità. La più importante, che abbiamo già avuto modo di conoscere, è la prima, che consente di specificare quale versione delle API (nel gergo di Android, “API Level“) vogliamo utilizzare:
Chi volesse scrivere un’applicazione per Android 1.0 e 1.1 (API Level 1 e 2, rispettivamente) rimarrà deluso: non è, infatti, possibile selezionare l’apposita versione delle API, per cui Android 1.5 rappresenterà necessariamente il requisito minimo.
A parte gli scherzi (chi volesse, potrebbe sempre procurarsi le precedenti versioni dell’SDK), il nocciolo della questione si presenta subito e rappresenta la classica domanda che un programmatore si pone quando deve iniziare un nuovo progetto: quale versione scegliere?
La risposta è scontata: dipende dagli obiettivi che ci si pone. Per cui un programmatore scanzonato e che non deve dar conto a nessuno, se non a se stesso, potrà decidere di smanettare con ciò che vuole.
Un professionista che ha ricevuto un progetto da portare avanti (con tanto di famigerata scadenza) non può permettersi tutta questa flessibilità (e nemmeno ce l’ha: alla fine non è certo lui a scegliere il target), per cui andrà in primis a controllare la situazione del mercato:
Tolti di mezzo i tablet (che hanno sostanzialmente un mercato a sé), la situazione è abbastanza chiara: si possono eliminare tutte le API Level fino alla 6, inclusa la 9 che è stata una meteora sparita velocemente, ma non si possono ignorare la 7 (13% è una fetta consistente di utenza ancora attiva, nonché potenziale cliente), 8 e 10.
La scelta di un’API rimane un’operazione molto dolorosa, da qualunque punto di vista la si veda. Da quello del produttore, perché tagliare equivale a dover fare a meno di quote di mercato. Da quello del programmatore, che vorrebbe utilizzare nuove API che gli semplificano la vita e si vede costretto a ripiegare su quello che offre quel particolare SDK.
Un esempio di quest’ultimo è rappresentato da Froyo (Android 2.2 / API Level) 8, che ha introdotto una nuova libreria / framework (Stagefright) per la gestione del multimedia (sebbene ci sia qualche problema, in quanto non risulta abilitata in tutti i dispositivi che montano questa versione): se ne dovrà fare a meno, continuando a sbattersi con la precedente soluzione (OpenCore, che non gode di particolare stima dagli addetti ai lavori).
La stabilità delle API, citata nel precedente articolo, dipende anche da questo: fornire a chi sviluppa strumenti che non cambiano troppo e troppo velocemente nel tempo. La buona fattura è anch’essa importante, ed è incomprensibile che, per fare un esempio veramente grossolano, soltanto da Android 3.0 (API Level 11) sia possibile cambiare da XML l’alpha channel (opacità / trasparenza) di un widget, costringendo quindi a ricorrere al solito, verboso da morire, codice Java…
Anche la grafica riveste un ruolo fondamentale, tant’è che le moderne applicazioni mobile tendono a essere particolarmente curate da questo punto di vista. Molto tempo viene speso soltanto per raggiungere quest’obiettivo (non particolarmente gradito ai programmatori, che tante volte devono improvvisarsi “designer”; ruolo che non è certo il loro), tenendo anche conto delle diverse risoluzioni esistenti per gli schermi in dotazione.
La gestione della grafica, intesa sia come disposizione dei widget nello schermo che come immagini a corredo dell’applicazione, è abbastanza complessa ed esula dagli scopi di quest’articolo. In maniera estremamente semplice e a puro titolo divulgativo, possiamo dire che Android prevede alcune tipologie di asset di riferimento dalle quali recuperare ciò che serve in base all’effettiva risoluzione del dispositivo corrente.
Sempre tralasciando il discorso dei tablet, per i telefonini sono previsti 3 tipi di asset: ldpi, mdpi, hdpi. Il primo rappresenta il riferimento per gli schermi 240×320, il secondo per quelli 320×480, mentre l’ultimo 480×800. In linea teorica sarebbe possibile mettere a disposizione un solo asset, lasciando poi il compito ad Android di scalare opportunamente le immagini per lo schermo di destinazione.
Praticamente questa strada è assolutamente consigliata per diverse ragioni. La prima è che gli aspect ratio risultano abbastanza diversi fra di loro (0,75, 0,67, e 0,6 rispettivamente), per cui il processo di adattamento introdurrebbe di fatto delle aberrazioni visive che possono risultare fastidiose. Soprattutto al collega grafico, particolarmente attento a che il suo lavoro non venga giustamente snaturato, che potrebbe quindi anelare al vostro scalpo.
Il secondo è rappresentato dalla qualità del risultato finale: un’immagine pensata per la 240×320 risulterebbe troppo sgranata a 480×800 a causa della mancanza di dettagli dovuta alla più bassa risoluzione. Una pensata per la 480×800 sarebbe povera di dettagli e un po’ pasticciata a causa della necessità di dover tagliare buona parte dell’informazione e scegliere un campione più o meno rappresentativo di quella originale.
La realtà risulta, però, ben diversa, e i dispositivi non si limitano a quelle 3 risoluzioni, com’è possibile vedere dalla voce “Skin” citata all’inizio dell’articolo:
A complicare ulteriormente le cose, a seconda dell’API Level è presente il supporto a determinate risoluzioni oppure. Ad esempio l’API Level 3 prevede le seguenti:
Mentre la 13 soltanto questa (ma ricordiamo che è riservata ai tablet):
Fortunatamente Android mette a disposizione uno strumento per cercare di adattare la grafica a seconda della risoluzione: le 9-patch. In sintesi, si tratta di immagini realizzate secondo un preciso schema che consente di definire quali parti delle medesime devono rimanere rigorosamente invariate (per non deformare la grafica) e quali possono essere “allungate” (replicate, per la precisione) per riempire lo spazio a disposizione. L’esempio presente alla fine del link vale più di mille parole.
Si tratta di un’idea semplice e geniale, sicuramente molto utile, ma che ha pure i suoi limiti (la pietra filosofale in informatica non è stata ancora inventata). Innanzitutto le parti fisse possono risultare troppo grandi su display piccoli (es: bordi troppo spessi, che mangiano troppo spazio), oppure troppo piccole su display grandi (es: bordi troppo esili e di difficile individuazione).
A parte questo, le 9-patch possono essere impiegate soltanto laddove sia necessario riempire lo sfondo (background) di un widget, quale potrebbe essere un bottone o una casella di testo, ad esempio. Non è, però, possibile ricorrervi nel caso di immagini con precisi disegni (stelline, lenti d’ingrandimento, frecce, ecc., ma anche loghi), che non possono certo essere “stirati” (vedi collega grafico di cui sopra).
Brevemente, l’ultima voce, Hardware, permette di specificare un insieme di caratteristiche da un nutrito elenco per il dispositivo da emulare:
Va sottolineata la differenza rispetto alle altre due: laddove si trattava di una singola scelta fra un insieme, qui si tratta di scegliere un insieme di caratteristiche fra tutte quelle a disposizione, il che fa letteralmente esplodere il numero di combinazioni possibili e i relativi test necessari a carico degli sviluppatori (anche se nessuno sano di mente si metterebbe a testare proprio tutte le combinazioni, ma solo quelle più “plausibili” o in ogni caso “comuni”).
Ci sono, poi, due diverse valutazioni da fare, che possono sembrare complementari, ma che in realtà sono legate e “compenetranti”. La prima è che se un’applicazione ha bisogno di rilevare le coordinate geografiche, il dispositivo dovrà necessariamente mettere a disposizione hardware adeguato allo scopo (GPS, AGPS, o una combinazione dei due). Poco male: è ovvio che l’applicazione non girerà in mancanza, e che quindi si perderà una parte del mercato per forza di cose, perché non si può certo modificare il target.
Per contro, l’assenza di una caratteristica può determinare scelte anche molto diverse, e influisce sicuramente sulla creatività e la possibilità di sperimentare tirando fuori un prodotto innovativo. E’ anche facile intuire il perché: se, ad esempio, il “GPS” non è in dotazione a tutti, si tenderà a toglierlo di mezzo per arrivare a un minimo comune denominatore che consenta di abbracciare il più ampio market share.
Il risultato netto è che sarebbe sostanzialmente inutile perdere tempo cercando di capire come sfruttare strumenti come questi, perché non fanno parte delle caratteristiche di “base”, standard, della piattaforma, e pertanto disponibili ovunque.
E’ scontato che questa libertà di scelta di cosa inserire o meno in un dispositivo si traduca in un mercato più variegato e in grado di coprire fasce molto ampie, dalle più economiche ma scarne, alle più costose ma ben carrozzate. Ma è anche vero che l’assenza di un minimo comune denominatore sufficiente ampio (ricco?) può minare la qualità dei prodotti finali fruibili dall’utenza, per quanto detto sopra.
Infine se, nonostante tutta questa disquisizione, non ci si fosse ancora convinti della (notevole) frammentazione di questa piattaforma mobile, riusciranno forse le recenti dichiarazioni di Rubin & soci riguardo alla prossima versione di Android, Ice Cream Sandwich:
…and it’s putting a stop to Android fragmentation…
There’s nothing worse than your friends having a more recent Android version than what you have, and thus getting cool new features. Google said they want “one OS that runs everywhere.” They’re going to do this by adapting the framework and adding new APIs “to help developers optimize for all various devices.”
Personalmente mi sfugge come si possa arginarla introducendo nuove API. Inoltre un’altra grande pecca di Android è che i dispositivi non sono tutti aggiornati all’ultima versione; anzi, a volte non è proprio possibile farlo. Ed è proprio questo il motivo per cui si cerca, al solito, il livello minimo delle API. Magari sarà un mio limite, per cui aspetto chiarimenti in merito, ma al momento la situazione rimane tutt’altro che rosea…
P.S. Sicuramente salterà all’occhio la mancata citazione dei layout relativi, che aiutano nella disposizione dei widget a seconda delle diverse risoluzioni. Non sono un’esclusiva di Android, per cui non aveva senso parlarne; al contrario delle 9-patch.