In occasione del Google I/O 2014, il principale evento mondiale sulle tecnologie di Mountain View, è stato annunciato Android L, nuova
versione del sistema operativo mobile più diffuso.
Secondo tradizione, le distribuzioni Android prendono il nome di qualcosa di “dolce” seguendo, nel tempo, un rigoroso ordine alfabetico. Il capostipite
degli Android “4” è stato Ice Cream Sandwich, poi sono arrivati Jelly Bean e KitKat. Ora tocca alla lettera L: è nato quindi Android L. L, con tutta
probabilità, come Lollipop.
In attesa che il nuovo sistema invada il mercato dell'elettronica, il suo SDK è stato pubblicato in anteprima, permettendo agli
sviluppatori di apprezzarne le innovazioni.
Questo articolo propone una panoramica delle principali novità introdotte, per lo più concentrate attorno alle maggiori problematiche della programmazione
mobile: usabilità e reattività delle interfacce utente, prestazioni e risparmio energetico. Nella parte finale, infine, daremo uno sguardo al codice, sperimentando in un breve esempio alcuni nuovi componenti.
Le principali novità
Le novità più salienti della nuova versione di Android sono:
-
adozione sempre più estesa dell'ambiente di runtime ART, la macchina virtuale che consente l’esecuzione della applicazioni scritte in
Java. Sin dal primo rilascio di Android, questo compito è stato svolto da Dalvik, affiancato solo in via sperimentale da ART (acronimo di Android Runtime) a partire dalla versione 4.4 del sistema. Con Android L, ART assume un'importanza
fondamentale divenendone di fatto l'ambiente di runtime di default; -
Material design: una filosofia di progettazione di interfacce che sta invadendo il mondo Google. I suoi progettisti hanno predisposto
anche un sito Internet apposito per presentarne le novità. Material
design ispira anche il tema di Android L, come vedremo nell'esempio successivo in questo articolo, e sarà sempre più utilizzato nelle applicazioni per il
nuovo sistema.
Secondo le intenzioni dei suoi ideatori, si tratta di un concentrato di principi di “buona progettazione di interfacce”, applicati con quanto di
meraviglioso la tecnologia informatica permette oggi. Fluidità, animazioni ed effetti sono gli strumenti messi a disposizione, ma lo scopo ultimo è
risolvere l'annoso problema delle interfacce Android, permettendo il massimo dell' adattabilità delle applicazioni alla moltitudine di dispositivi supportati, indipendentemente da risorse a disposizione, dimensioni e
densità del display; -
Insieme al Material design, sono stati introdotti due nuovi widget: uno, RecyclerView, spicca a livello progettuale in
quanto ridefinisce il concetto di AdapterView mirando ad un uso ottimizzato delle risorse; l'altro, CardView, consente
un'elegante presentazione delle informazioni.
I due nuovi widget sono accompagnati da altre novità nel campo delle animazioni e degli effetti, con il nuovo fattore elevation che regola, tra
l'altro, la proiezione delle ombre dei componenti; -
Importanti novità anche nelle Notification. Già nella programmazione attuale delle app Android, le notifoche svolgono un ruolo
importante in quanto sono una forma di comunicazione con l'utente che si manifesta al di fuori delle applicazioni e con tempistiche che permettono di
evadere dal normale flusso di esecuzione. Le Notification in Android L si arricchiscono di nuovi dettagli, appaiono nella forma heads-up
per essere più immediate in casi di urgenza particolare e possono figurare in due layout differenti, Base Layout ed Expanded Layout.
Queste sono solo le novità più evidenti, ma le nuove feature aggiunte in Android L riguardano anche altri campi, dal multimedia allo storage,
dall'efficienza energetica alla comunicazione.
Preparare l'ambiente di lavoro
Piuttosto che procedere con ulteriori descrizioni sommarie di aspetti progettuali, iniziamo subito a lavorare in Android L, sperimentando i nuovi widget
per interfacce utente. Prima di procedere con l'esempio, dobbiamo approntare un ambiente di lavoro, mettendo a disposizione dell'IDE un SDK aggiornato e configurando un emulatore per i test.
È bene specificare che l'esempio illustrato è stato preparato con Android Studio, ambiente che appare sempre più consono alle necessità
dello sviluppatore. I concetti discussi ed il codice proposto potranno comunque essere sperimentati parimenti su Eclipse ADT.
La prima cosa da fare è scaricare il SDK. Il tool da utilizzare è il classico SDK Manager, che tutti gli sviluppatori Android avranno
imparato a conoscere. Tramite quest’ultimo tool, richiediamo il download di due tipologie di elementi:
- nella sezione Tools, selezioniamo gli ultimi SDK Tools, Platform-Tools e Build-Tools;
- nella sezione Android L (API 20, L preview) avremo bisogno almeno di un SDK Platform ed un'immagine per l'emulatore.
Selezionati gli elementi indicati, clicchiamo su Install packages e procederemo all'installazione. Al termine di quest’ultima, potremo creare i
due strumenti di lavoro necessari: un progetto Android nel nostro IDE ed un emulatore.
Per quanto riguarda il progetto, per essere sicuri di testare il nuovo SDK, dovremo valorizzare come segue alcune variabili:
Variabile | Valore |
---|---|
compileSdkVersion |
android-L |
minSdkVersion |
L |
targetSdkVersion |
L |
Tali impostazioni normalmente saranno immesse direttamente nel file AndroidManifest.xml se si usa Eclipse ADT, altrimenti nel file build.gradle se si è optato per Android Studio.
L'emulatore dovrà essere creato impostando come target Android L Preview, e scegliendo come immagine di sistema una di quelle
scaricate nel SDK Manager.
Utilizzare le nuove funzionalità: un esempio
In questo paragrafo proponiamo un esempio che mostra l’utilizzo del nuovo tema Material, e di entrambi i nuovi widget, RecylerView e CardView su Android L.
Il tema è stato impostato mediante gli stili, in particolare mediante il file /res/values/styles.xml. Eccone il contenuto:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar"/>
</resources>
Il Material Theme potrebbe essere personalizzato impostando, ad esempio, i colori dell'Action Bar e della barra di navigazione, nonché
quelli dello sfondo della finestra e del titolo dell'applicazione. Al momento però non ci occuperemo di questi dettagli.
Per fornire ora un esempio di come utilizzare i nuovi widget, abbiamo bisogno di utilizzare gli AdapterView, e per questo ci
serviremo di un’Activity. Il codice che vedremo usa come sorgente un array di oggetti di classe Persona, prodotte staticamente, e le pubblica in
un RecyclerView. Ogni elemento presentato sarà una CardView. Il risultato finale è visibile nella figura seguente.
I nuovi widget sono visibili nei layout. In quello adottato dall'Activity, avremo un RecyclerView:
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Ogni singolo elemento che popola la lista è costituito da una CardView con all'interno due TextView:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_margin="5dp"
card_view:cardCornerRadius="25dp"
card_view:cardBackgroundColor="@android:color/holo_orange_light"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:background="?android:selectableItemBackground"
android:focusable="true"
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/nomecompleto"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
/>
<TextView
android:id="@+id/eta"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"/>
</LinearLayout>
</android.support.v7.widget.CardView>
Si faccia attenzione al fatto che entrambi i nuovi widget – RecyclerView e CardView – fanno parte della libreria di supporto. Per averli
a disposizione, è necessario scaricarli ed includerli nel proprio SDK. Se si sta utilizzando Android Studio, è sufficiente sfruttare le potenzialità di
Gradle inserendo nel file build.gradle le seguenti righe, all'interno del nodo dependencies:
[code]
compile 'com.android.support:recyclerview-v7:+'
compile 'com.android.support:cardview-v7:+'
[/code]
Se, al contrario, si sta utilizzando Eclipse ADT, lo si dovrà fare in maniera manuale aggiornando mediante SDK Manager i pacchetti Android Support Library e Android Support Repository all'ultima versione, e cercando all'interno della cartella Extras dello SDK
gli archivi .jar che contengono le classi CardView e RecyclerView. Una volta individuati, possono essere inclusi nel build path
del progetto.
Per quanto riguarda il codice Java, la classe di esempio che chiamiamo Persona contiene solo pochi dati simbolici:
public class Persona
{
private String nome;
private String cognome;
private int eta;
/*
OMISSIS: tutti i getter e setter relativi ai membri privati
*/
public String getNomeCompleto()
{
return nome+" "+cognome;
}
public String getEtaCompleta()
{
return "Anni "+eta;
}
}
L'Activity per lo più conterrà la configurazione del RecyclerView e del suo collegamento con l'Adapter:
public class MyActivity extends Activity {
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
adapter = new MyAdapter(generaPersone());
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
private Persona[] generaPersone()
{
Persona[] persone=new Persona[3];
/*
OMISSIS: popola staticamente l'array di oggetti Persona
*/
return persone;
}
}
L'Adapter è probabilmente la classe che mostra le maggiori novità:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private Persona[] lista;
public static class ViewHolder extends RecyclerView.ViewHolder
{
public TextView nomeCompleto;
public TextView eta;
public ViewHolder(View v)
{
super(v);
nomeCompleto= (TextView) v.findViewById(R.id.nomecompleto);
eta= (TextView) v.findViewById(R.id.eta);
}
}
public MyAdapter(Persona[] dataset) {
lista = dataset;
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.nomeCompleto.setText(lista[position].getNomeCompleto());
holder.eta.setText(lista[position].getEtaCompleta());
}
@Override
public int getItemCount() {
return lista.length;
}
}
La maggiore rilevanza riguarda RecyclerView, che svolge un ruolo simile ad un tipico AdapterView ma non cura gli aspetti visuali.
Ciò è dimostrato dal fatto che gli viene passato un riferimento ad un LayoutManager nel metodo onCreate dell'Activity.
Come il suo nome stesso dichiara, il RecyclerView si occupa di riciclare, riutilizzare le View che l'Adapter produce. Per apprezzare il
lavoro che svolge è importante avere ben chiaro il rapporto che intercorre tra un AdapterView e un Adapter. A tal proposito segnaliamo la
possibilità di approfondire questo aspetto sfruttando la Guida Android di HTML.it.
Riepiloghiamo velocemente. Nel momento in cui scorriamo una lista di elementi all'interno di un'Activity, le View che compongono le righe mostrate
sono sempre le stesse. L'impressione che la lista scorra è data dalla sostituzione dei dati che avviene nelle View. Quindi, gestendo un AdapterView in maniera efficiente dovremmo saper distinguere le fasi in cui la View viene creata (Create) e quelle in cui
vengono associati i dati ad essa (Bind).
Inoltre esiste un pattern detto ViewHolder, da sempre consigliato dalla documentazione ufficiale ma spesso poco apprezzato dagli
sviluppatori. Si tratta di un modo per conservare riferimenti ai widget interni ad una View. Un oggetto ViewHolder viene collegato allaView corrispondente per svolgere un ruolo simile a quello di una cache, con l'effetto di ridurre al minimo indispensabile le invocazioni al metodo findViewById.
La classe Adapter, definita all'interno del RecyclerView, obbliga a tenere in considerazione tutti questi aspetti, distinguendo bene le
fasi di Create e Bind e utilizzando il pattern ViewHolder. Viene pertanto richiesta l'implementazione di due metodi:
-
onCreateViewHolder: viene creata una nuova View mediante inflating. La View prodotta viene passata al costruttore
della classe ViewHolder dove si troveranno le uniche invocazioni al metodo findViewById; -
onBindViewHolder: è il momento in cui i dati vengono associati alla View. Si faccia attenzione al fatto che tale associazione
avviene tramite ViewHolder, il quale offre già i riferimenti ai widget presenti nelle singole righe.
Per completare il commento all’esempio presentato, la CardView è stata usata per definire graficamente gli elementi all'interno della
lista. Vale la pena notare che sono stati impostati due attributi: cardBackgroundColor e cardCornerRadius che, rispettivamente,
permettono di impostare il colore di sfondo e l'arrotondamento degli angoli.
Conclusioni
Quanto presentato nell'articolo ha lo scopo di proporre un approccio rapido allo sviluppo sulla nuova versione di Android, sebbene si
tratti di una preview, e quindi non sono da escludere prossimi ampliamenti e correzioni.
È importante sin da subito prendere confidenza con i nuovi aspetti, non solo a livello pratico ma cercando di trarre indicazioni sulle linee di evoluzione
del sistema operativo. Una soluzione per il domani mette in evidenza una problematica di oggi, fornendo allo sviluppatore idee per migliorare il proprio
lavoro attuale. Gli spunti di riflessione che offre, ad esempio, il caso del RecyclerView, ne sono la prova.