Android Programmazione avanzata - CAT@logo CNR
←
→
Trascrizione del contenuto della pagina
Se il tuo browser non visualizza correttamente la pagina, ti preghiamo di leggere il contenuto della pagina quaggiù
Fabio Collini Matteo Bonifazi, Alessandro Martellucci, Stefano Sanna Android Programmazione avanzata NUO IZIONE ED BE 2a LLER ES TSE B Sviluppo multidevice >> Android Wear, Chromecast, Bluetooth Low Energy >> Programmazione funzionale con RxJava >> Testing e qualità del codice >>
Android Programmazione avanzata Seconda edizione Fabio Collini Matteo Bonifazi, Alessandro Martellucci, Stefano Sanna
Android | Programmazione avanzata Seconda edizione Autori: Fabio Collini, Matteo Bonifazi, Alessandro Martellucci, Stefano Sanna Collana: Editor in Chief: Marco Aleotti Progetto grafico: Roberta Venturieri Immagine di copertina: © scanrail | Thinkstock © 2015 Edizioni Lswr* – Tutti i diritti riservati ISBN: 978-88-6895-071-2 I diritti di traduzione, di memorizzazione elettronica, di riproduzione e adattamento totale o parziale con qualsiasi mezzo (com- presi i microfilm e le copie fotostatiche), sono riservati per tutti i Paesi. Le fotocopie per uso personale del lettore possono essere effettuate nei limiti del 15% di ciascun volume dietro pagamento alla SIAE del compenso previsto dall’art. 68, commi 4 e 5, della legge 22 aprile 1941 n. 633. Le fotocopie effettuate per finalità di carattere professionale, economico o commerciale o comunque per uso diverso da quello personale possono essere effettuate a seguito di specifica autorizzazione rilasciata da CLEARedi, Centro Licenze e Autorizzazioni per le Riproduzioni Editoriali, Corso di Porta Romana 108, 20122 Milano, e-mail autorizzazioni@clearedi.org e sito web www.clearedi.org. La presente pubblicazione contiene le opinioni dell’autore e ha lo scopo di fornire informazioni precise e accurate. L’elaborazione dei testi, anche se curata con scrupolosa attenzione, non può comportare specifiche responsabilità in capo all’autore e/o all’edi- tore per eventuali errori o inesattezze. L’Editore ha compiuto ogni sforzo per ottenere e citare le fonti esatte delle illustrazioni. Qualora in qualche caso non fosse riuscito a reperire gli aventi diritto è a disposizione per rimediare a eventuali involontarie omissioni o errori nei riferimenti citati. Tutti i marchi registrati citati appartengono ai legittimi proprietari. Via G. Spadolini, 7 20141 Milano (MI) Tel. 02 881841 www.edizionilswr.it Printed in Italy Finito di stampare nel mese di giugno 2015 presso “Rotolito Lombarda” S.p.A., Pioltello (MI) (*) Edizioni Lswr è un marchio di La Tribuna Srl. La Tribuna Srl fa parte di .
Sommario PREFAZIONE............................................................................................................... 9 INTRODUZIONE........................................................................................................11 1. ACTIVITY E TASK IN BACKGROUND di Fabio Collini.................................17 Ciclo di vita di una Activity.......................................................................................................17 Gestione dei metodi di callback comuni a più Activity.................................................... 18 Flusso delle callback del ciclo di vita di una Actvity..........................................................22 Salvataggio dello stato di una Activity.................................................................................23 Generazione automatica delle implementazioni di Parcelable................................................................................................................................26 Tipi di dati da salvare in una Activity....................................................................................28 UI Thread e concorrenza..........................................................................................................29 Tipologie di task in background..............................................................................................33 AsyncTask e Loader...................................................................................................................34 IntentService e LocalBroadcastManager.............................................................................35 EventBus ed Executor................................................................................................................ 41 2. PROGRAMMAZIONE FUNZIONALE di Fabio Collini.................................47 Lambda expression e method reference............................................................................. 48 Retrolambda.................................................................................................................................51 Linguaggi alternativi a Java su Android................................................................................52 Manipolazione di dati con gli Stream di Java 8..................................................................53 RxJava...........................................................................................................................................57 Flussi di dati asincroni................................................................................................................61 Gestione delle Subscription.................................................................................................... 66 Gestione degli errori................................................................................................................. 68 Chiamate a servizi REST con Retrofit.....................................................................................71 Combinare più flussi di dati con RxJava...............................................................................73 Hot e cold Observable............................................................................................................. 80 Manipolazione di flussi di dati............................................................................................... 84 Utilizzo dei Subject................................................................................................................... 86 Eventi della UI con RxJava........................................................................................................92 Gestione dei nested Observable........................................................................................... 94 Task in background collegati al ciclo di vita di una Activity........................................... 96 5
Android | Programmazione avanzata 3. GRAFICA E INTERFACCIA UTENTE di Fabio Collini.................................109 Density e screen size...............................................................................................................109 Immagini 9patch........................................................................................................................111 Drawable complessi..................................................................................................................111 Custom View per implementare un flat Button................................................................115 Immagini Mipmap.....................................................................................................................117 Vector Drawable........................................................................................................................117 Organizzazione delle risorse..................................................................................................118 Canvas, Paint e Shader.............................................................................................................121 Color filter.................................................................................................................................. 126 Utilizzo delle Custom View per migliorare le performance...........................................128 Animazioni Android 2.x.......................................................................................................... 136 Animazioni Android 3.0......................................................................................................... 138 Animazioni Android 4.4.........................................................................................................143 Animazioni Android 5.0.........................................................................................................144 Gestione degli eventi touch...................................................................................................148 Drag di una View con animazioni........................................................................................150 4. SUPPORTO MULTIDEVICE di Fabio Collini................................................. 157 Dimensioni degli schermi dei dispositivi Android........................................................... 157 Gestione delle risorse al variare della dimensione dello schermo.............................. 159 Gestione della orientation...................................................................................................... 162 Gestione dei layout in base alla larghezza dello schermo............................................. 163 Adattamento di un layout in base alle dimensioni.......................................................... 163 Utilizzo dei Fragment...............................................................................................................164 Gestione di una Activity multiFragment............................................................................ 167 Gestione delle transaction..................................................................................................... 172 Altri utilizzi dei Fragment....................................................................................................... 174 Activity con singolo Fragment.............................................................................................. 174 Custom View Vs Fragment.................................................................................................... 176 5. BLUETOOTH di Stefano Sanna........................................................................ 179 L’ultimo immortale................................................................................................................... 179 Bluetooth Classic e Bluetooth Low Energy........................................................................180 Panoramica del protocollo Bluetooth Classic................................................................... 182 Panoramica del protocollo Bluetooth Low Energy...........................................................189 Setup per sperimentazione.................................................................................................... 195 Bluetooth Classic su Android...............................................................................................209 Attivazione e visibilità.............................................................................................................210 Discovery dei dispositivi ........................................................................................................ 212 Pairing......................................................................................................................................... 216 Discovery dei servizi................................................................................................................ 219 Apertura diretta di connessioni RFCOMM....................................................................... 222 Bluetooth Low Energy su Android....................................................................................... 223 Bluetooth beacon.................................................................................................................... 230 6
Sommario La tecnologia iBeacon............................................................................................................ 232 Implementazione di un beacon........................................................................................... 235 Scansione dei beacon in ambiente Android..................................................................... 238 Beacon e geofencing............................................................................................................... 242 Inversione di ruoli.................................................................................................................... 243 Sicurezza e privacy................................................................................................................. 245 6. ANDROID WEAR di Matteo Bonifazi............................................................ 249 Android Wear idea..................................................................................................................250 Android Wear design............................................................................................................. 252 Notifiche tramite Android Wear......................................................................................... 255 Android Wear App.................................................................................................................. 265 Android Wear Watch face.................................................................................................... 287 7. CHROMECAST E GOOGLE CAST di Alessandro Martellucci................... 305 Che cos’è il Chromecast........................................................................................................ 305 Installazione e configurazione.............................................................................................306 Chromecast App..................................................................................................................... 307 Google Cast............................................................................................................................... 313 Applicazione Sender................................................................................................................314 Il bottone di Cast...................................................................................................................... 318 Il media router framework..................................................................................................... 319 Il ruolo del Google Play Services.......................................................................................... 331 La gestione del receiver da parte dell’applicazione client..............................................333 La riproduzione del contenuto.............................................................................................340 La comunicazione tra le applicazioni................................................................................. 345 Il controllo del volume............................................................................................................ 350 I sottotitoli.................................................................................................................................. 351 Il logging.................................................................................................................................... 354 Applicazione receiver............................................................................................................. 354 Applicazione receiver: concetti avanzati........................................................................... 363 Tipi e formati supportati........................................................................................................ 369 Android TV............................................................................................................................... 370 8. QUALITÀ DEL CODICE di Fabio Collini........................................................375 Build dei progetti con Gradle.................................................................................................375 Testing del codice.................................................................................................................... 378 Tipologie di testing................................................................................................................. 379 Unit test con JUnit................................................................................................................... 381 Test di integrazione................................................................................................................. 387 Robolectric................................................................................................................................ 387 Testing end to end................................................................................................................... 389 Acceptance test....................................................................................................................... 396 Monkey testing........................................................................................................................ 397 Copertura dei test................................................................................................................... 397 7
Android | Programmazione avanzata Analizzatori statici del codice.............................................................................................. 398 Continuous Integration.......................................................................................................... 399 Strategia di test di una applicazione Android..................................................................402 Testing di codice legacy.........................................................................................................402 Servizi web remoti.................................................................................................................. 404 Dependency injection............................................................................................................405 Dagger.........................................................................................................................................412 Testing di codice dipendente dal tempo............................................................................ 425 Testing su Java Virtual Machine di una applicazione Android....................................426 Testing della UI con Espresso............................................................................................... 433 Model View Presenter........................................................................................................... 435 Task asincroni con Model View Presenter e RxJava.......................................................447 Oggetti fake con Javassist.....................................................................................................450 BDD e TDD con Espresso e Model View Presenter....................................................... 455 APPENDICE: SICUREZZA................................................................................... 457 La sicurezza nell’azienda....................................................................................................... 457 Utilizzo delle WebView.........................................................................................................463 Android permission................................................................................................................468 INDICE ANALITICO............................................................................................. 475 8
Prefazione Quando gli autori di Android - Programmazione avanzata mi hanno chiesto di scrivere la prefazione alla nuova edizione, il mio pensiero è andato immediatamente ai nu- meri impressionanti che il sistema operativo di Google ha macinato in questi ultimi anni, alla strada percorsa dal lancio del 2008 sul primo dispositivo targato HTC. Senza voler entrare nel dettaglio dei singoli dati, basti pensare che, secondo le stime di IDC, negli ultimi due anni circa 80 smartphone venduti su 100 sono stati equipag- giati con il sistema operativo del robottino. Proiettato su scala globale, questo dato significa un mercato potenziale di centinaia di milioni di persone. Significa inoltre che, attorno al 2018, il fatturato delle app per Android supererà quello generato dal principale concorrente, iOS di Apple. Non a caso, Flipboard ha lanciato la propria versione per Android due anni dopo la versione per iOS, ma in poco più di un anno la metà degli accessi arriva ormai da smartphone Android. La motivazione per imparare a programmare applicativi per Android, però, non deve limitarsi alla metrica numerica. Perché leggere – e studiare – un volume dedicato a chi sviluppa in maniera avanzata per Android? La risposta sta nell’impressionante successo e nelle previsioni di cre- scita future, certo. Un volume che tratta argomenti comuni per gli sviluppatori, con un approccio fuori dal comune, e si spinge a trattare argomenti che i classici testi di programmazione per Android spesso non considerano, non avrebbe un senso se non nella convinzione che “Google stia per conquistare le nostre vite”, per riprendere le parole di Fastcode. Provenendo dal mondo delle Telco, dove ho avuto la fortuna di lavorare al lancio della prima rete UMTS al mondo, del primo cellulare con TV digitale mobile e del primo Skypephone low cost, quando ancora gli smartphone non erano così diffusi, il sistema operativo Android non è qualcosa di nuovo. Prima ancora, come giornalista tecnologico, ho avuto l’opportunità di vivere le principali trasformazioni della telefo- nia mobile, tra cui il declino dei sistemi operativi proprietari e l’esplosione delle app. 9
Android | Programmazione avanzata Negli ultimi due anni sono successe, però, diverse cose che mi hanno fatto compren- dere quanto pervasivo possa essere – parallelamente all’avanzata dell’Internet degli oggetti – un sistema operativo così versatile e diffuso. Sono stato tra i pochi italiani a poter ricevere i Google Glass durante il programma Explorer, e Android Auto è qualcosa su cui ho lavorato negli ultimi 24 mesi per il debutto di Google nel mondo dell’auto. È da questo punto di vista, come osservatore privilegiato, che ho imparato ad ap- prezzare Google come un risolutore di problemi in (quasi) ogni ambito della nostra vita, una presenza amorfa che il Material Design – l’unificazione di tutti i prodotti Google e app di terze parti sotto un unico cappello – rende concreta e possibile, un sistema operativo che rompe le regole logiche e fisiche note fino a oggi per ri- disegnare completamente il mondo che ci circonda. Un Google che da prodotto si trasforma in presenza, con la giusta informazione sullo schermo giusto al momento giusto. Cellulari, auto, console gaming, schermi del desktop, computer portatili, we- arable e (forse) occhiali. In un mondo così variegato, la completa padronanza del sistema operativo targato Google è fondamentale per chi sviluppa applicativi complessi. Alessandro, Fabio, Matteo e Stefano ci guidano, attraverso i capitoli di Android Programmazione Avan- zata, nell’esplorazione di questo mondo affascinante e allo stesso tempo complesso. Per chi condivide la visione sul futuro di Android (e Google), sviluppando applicativi articolati, conoscerne gli anfratti più nascosti non può che rappresentare una tappa fondamentale del proprio percorso professionale. Massimo Cavazzini Global Uconnect – Head of Marketing&User Experience EMEA region Fiat Chrysler Automobiles 10
Introduzione Questo libro parla di una scommessa vinta. Android è il sistema operativo per dispo- sitivi mobili più diffuso al mondo. In realtà, non solo dà vita a smartphone e tablet, ma è presente in smartwatch, apparati televisivi, autovetture e sistemi embedded. E non solo in prodotti commerciali, ma anche in progetti indipendenti, vista la sua natura open source. L’ecosistema di Android si arricchisce costantemente di nuove API, nuove librerie, nuovi strumenti di sviluppo, nuovo hardware compatibile, nuove estensioni. Per la gioia degli sviluppatori e degli utenti. Sviluppatori motivati realiz- zano prodotti che entusiasmano gli utenti, che a loro volta aumentano la domanda di nuovi servizi e nuove applicazioni, che a sua volta alimenta la domanda di sviluppa- tori sempre più specializzati. È inevitabile: laddove c’è una tecnologia così pervasiva e ubiqua nella vita delle persone, in poco tempo si aprono spazi infiniti per nuove idee, nuove possibilità. L’obiettivo di questo libro è fornire agli sviluppatori che già conoscono le basi del- la programmazione su Android le conoscenze per affrontare problematiche meno comuni e trarre ispirazione dalle potenzialità più intriganti del sistema operativo. Partendo dalla propria esperienza professionale consolidata, gli autori hanno sele- zionato gli argomenti mirando alla crescita del lettore su due fronti: irrobustire la co- noscenza dei temi “core”, al fine di migliorare la propria padronanza della piattafor- ma (si vedano i temi sul supporto multidevice o la gestione dei task in background) e stimolare nuove esplorazioni sui temi più attuali (wearable e interazione con ap- parati televisivi). Gli argomenti discussi nei vari capitoli comprendono riferimenti non solo alle li- brerie standard di Android, ma anche ai molti progetti open source utilizzabili per lo sviluppo di applicazioni per questo sistema operativo. Negli ultimi anni, infatti, molte aziende (un tempo startup e adesso colossi spesso quotati in borsa) stanno rilasciando librerie open source che semplificano varie fasi dello sviluppo. Square è sicuramente una delle realtà più attive, ma anche Facebook, Yahoo!, Instagram 11
Android | Programmazione avanzata e NetFlix annoverano vari progetti open source attraverso i quali stanno facendo crescere varie community di sviluppatori. Un esempio molto significativo è quello di RxJava (affrontato nel capitolo dedicato alla programmazione funzionale), una libreria open source sviluppata da Netflix che sta rivoluzionando il modo di scrivere il codice delle applicazioni Android. In questo senso, pur se cristallizzato nelle sue pagine, questo libro è “vivo”, attualiz- zato non solo nella mera versione delle API, ma anche negli obiettivi. È interessante, infatti, notare come temi ritenuti avanzati nella prima edizione non lo siano più nella seconda: è il caso delle notifiche push, ormai consolidate sia client-side sia server- side, sulle quali è possibile trovare in rete numerosissimi esempi di codice e servi- zi gratuiti che implementano le funzionalità di backend (per esempio, parse.com). Altri, come NFC, hanno avuto poche evoluzioni (se non l’importante introduzione della modalità HCE) e rispetto alle aspettative di tre anni fa sono rimasti argomenti di nicchia. A chi si rivolge questo libro Questo libro è rivolto agli sviluppatori che hanno già una esperienza nello sviluppo di applicazioni Android e che vogliono migliorare le proprie skill di programmazione su questo sistema operativo mobile. Gli argomenti sono trattati partendo dal presuppo- sto che il lettore abbia una conoscenza dei principali concetti dello sviluppo di una applicazione Android. Gli autori Fabio Collini si occupa, all’interno dell’acceleratore di startup Nana Bianca di Firenze, dello sviluppo di varie applicazioni disponibili nel Play Store. Dopo una esperienza su piattaforma Java Enterprise, dal 2009 si occupa di progettazione e sviluppo di ap- plicazioni Android. È attivo nella community sia come blogger (ha fondato e scrive su cosenonjaviste.it) sia come speaker nelle principali conferenze a livello nazionale. Come freelance, ha rilasciato due applicazioni che hanno ottenuto un buon numero di download. Matteo Bonifazi è Senior Android developer di Open Reply (Gruppo Reply) e Google Developer Expert per la piattaforma Android. Ha partecipato alla realizzazione di im- portanti progetti Android in campo nazionale e internazionale, riguardanti lo sviluppo di applicazioni Android innovative e personalizzazioni del sistema operativo Android. Collabora attivamente con il Google Developer Group di Roma, dove si occupa prin- cipalmente di far conoscere alla comunità tutte le novità dell’ecosistema Android. È speaker per le più importanti conferenze italiane e internazionali. 12
Introduzione Alessandro Martellucci è laureato in Informatica e da diversi anni segue il mercato mobile, con particolare interesse per l’ecosistema Android. A oggi è Android deve- loper presso OpenReply, società del gruppo Reply, e partecipa a progetti con diverse peculiarità: dal video streaming all’installazione di Android su dispositivi con hardware personalizzato. Nel 2014 ha partecipato al Droidcon UK con un seminario dedicato al video streaming in Android, parlando del Chromecast e dell’Android TV. Stefano Sanna è attualmente Manager presso Open Reply (Gruppo Reply), dove coor- dina le attività di sviluppo di app native e ibride. Ha iniziato a sviluppare software per dispositivi mobili nel 1999, su un Psion 5MX. Da allora ha lavorato su Java Micro Edi- tion, Symbian, iOS e dal 2009 si occupa di Android per applicazioni commerciali. Ha scritto due libri sullo sviluppo mobile e tenuto numerosi seminari su Java, Android e Bluetooth in Italia e all’estero. Lasciati gli smartphone, ama giocare con i suoi bambini a costruire robot e navi spaziali con i LEGO. La struttura Il libro è diviso in otto capitoli, ognuno dei quali contiene la trattazione di un argomen- to specifico. In alcuni casi sono presenti riferimenti ad altri capitoli, per questo motivo è consigliata la lettura nell’ordine in cui sono proposti. Il Capitolo 1 descrive nel dettaglio il ciclo di vita delle Activity; pur essendo uno dei primi argomenti affrontati quando ci si avvicina ad Android, non è sempre facile da di- gerire. In questo capitolo sono affrontate le problematiche più comuni, prima fra tutte la gestione dei task in background. Il Capitolo 2 affronta la programmazione funzionale su Android: purtroppo ancora non è possibile utilizzare Java 8 per lo sviluppo di applicazioni Android, anche se, come mostrato in questo capitolo, Retrolambda è un’ottima alternativa. Gran parte di questo capitolo è dedicata al framework RxJava, mostrando sia i concetti base sia quelli più avanzati. La grafica e la gestione dell’interfaccia utente sono l’argomento del Capitolo 3. Que- sto capitolo contiene varie tecniche da utilizzare per sviluppare la parte di UI di una applicazione. Fra gli argomenti trattati ci sono i Drawable, le animazioni, i Canvas e la gestione degli eventi touch. Gestire al meglio le risorse è fondamentale (ma non sempre facile) per creare layout che si adattino ai vari dispositivi: il Capitolo 4 contiene un approfondimento su questo tema, con particolare riferimento alla gestione del supporto multidevice e all’utilizzo dei Fragment. L’argomento presentato nel Capitolo 5 è Bluetooth, con una dettagliata trattazione di Bluetooth Low Energy (BLE), la cui API ha fatto la sua comparsa su Android 4.3. BLE 13
Android | Programmazione avanzata consente l’interfacciamento a dispositivi indossabili (tra cui le varie “band” per il fit- ness) e, più in generale, è la tecnologia abilitante per la Internet Of Things. Tra il 2015 e il 2016 si prevede che il numero dei televisori connessi alla rete sfiorerà il miliardo di unità; Chromecast e Android TV (trattati nel Capitolo 6) rappresentano solo l’inizio di questa nuova era tecnologica che colpirà le nostre vite. Il supporto da parte di Mountain View, con il suo Google Cast, offre a tutti gli sviluppatori un mon- do di possibilità ancora inesplorate: l’On Demand, il Gaming e l’Entertainment sono solo alcuni tra gli argomenti più interessanti, sui quali tutti gli sviluppatori dovrebbero scommettere. Come cambia la user experience sui nostri polsi? Il Capitolo 7, dedicato ad Android Wear, mostra nel dettaglio come sarà possibile estendere le proprie applicazioni su tutti i nuovi smartwatch powered by Google. Il testing su Android è il principale argomento del Capitolo 8: la prima parte contiene una panoramica sui vari tool disponibili, da quelli per il testing fino a quelli per l’analisi statica del codice e la continuous integration. Nella seconda parte sono analizzate al- cune tecniche (come la dependency injection usando Dagger e il pattern Model View Presenter) da utilizzare per scrivere codice testabile. Completa il volume l’Appendice, dedicata alla sicurezza delle applicazioni Android; questo tema viene affrontato mostrando alcune funzionalità messe a disposizione dal sistema operativo utilizzabili per aumentare la sicurezza delle applicazioni Android. Risorse Sito web ufficiale del libro: http://www.androidavanzato.it Repository codice: https://github.com/androidavanzato E-mail per supporto e segnalazioni: androidavanzato@gmail.com Twitter: @androidavanzato Ringraziamenti Gli autori ringraziano l’editore per la fiducia riposta, in particolare Marco Aleotti per il suo supporto instancabile durante la scrittura e l’evoluzione dell’opera. Fabio ringrazia Letizia per averlo sopportato nonostante, durante la scrittura del libro, sia stato ancora più asociale del solito. Inoltre ringrazia Stefano per averlo coinvolto in questo progetto, e Matteo e Alessandro per aver arricchito, con i loro importanti contributi, gli argomenti trattati in questo libro. Matteo dedica il suo lavoro alle persone che lo hanno aiutato in modo diretto e indiret- to nella scrittura di questo libro. Push the limits! 14
Introduzione Alessandro ringrazia, in egual maniera, tutti coloro che lo hanno supportato e aiutato durante la stesura del libro. È grazie a loro se il suo contributo è oggi migliore rispetto a com’era all’inizio. Stefano ringrazia in primis Fabio: senza la sua enorme tenacia e solidissima prepa- razione questa seconda edizione non avrebbe conosciuto gli onori della stampa. Un grazie sincero va ad Alessandro e Matteo, che hanno accolto con entusiasmo questo progetto, contribuendo con temi freschi e appassionanti. Infine, dedica il risultato di questo lavoro ai piccoli Riccardo e Alessandro, la cui intuizione, nel chiedere “Papà, anche qui dentro c’è un piccolo computer?”, è misura della pervasività delle tecnologie raccontate in questo libro. 15
1 Activity e task in background di Fabio Collini Questo capitolo mostra nel dettaglio l’utilizzo delle Activity all’interno di una applicazione, ponendo particolare attenzione sull’esecuzione dei task in background. Sono analizzate le varie soluzioni disponibili: sia quelle contenute nel framework Android (come gli Async Task e gli Intent Service) sia quelle utilizzabili attraverso librerie di terze parti. Ciclo di vita di una Activity Il concetto di Activity è uno dei più importanti nello sviluppo di una applicazione An- droid ed è sicuramente il primo che ogni sviluppatore che si avvicina a questo siste- ma operativo apprende. Nei primi esempi, a una Activity corrisponde una schermata dell’applicazione; questa corrispondenza non è vera negli esempi più complessi, ma è comunque un buon modo per familiarizzare con il concetto di Activity. Scrivendo una applicazione Android che implementa il classico hello world, è necessa- rio creare una classe che estende Activity e riscrivere un solo metodo: onCreate. Que- sto metodo di callback viene invocato automaticamente in corrispondenza della cre- azione dell’Activity, e di solito contiene il codice per inizializzare l’interfaccia grafica. Il concetto di callback è ormai abbastanza comune a molti framework di sviluppo; in una applicazione Android uno sviluppatore non deve scrivere una classe con un metodo statico main invocato all’avvio. Un metodo main esiste, ma è nelle classi del framework Android, in particolare nella classe ActivityThread. In pratica, non sono le classi scritte 17
Android | Programmazione avanzata da uno sviluppatore che richiamano i metodi del framework; tali classi sono inserite all’interno del framework e contengono dei metodi (chiamati, appunto, di callback) richiamati in corrispondenza di alcuni eventi. Il principio che sta dietro questo modo di organizzare le classi è chiamato anche principio Hollywood e può essere enunciato con la frase don’t call me, I’ll call you. Il ciclo di vita di una Activity non è banale da gestire; per questo motivo, il metodo on- Create non è l’unica callback disponibile. Le callback principali sono sei; per analizzarle meglio è possibile raggrupparle a coppie: • onCreate/onDestroy: richiamati, rispettivamente, dopo la creazione e prima che l’Activity sia distrutta. Il metodo onCreate contiene solitamente la creazione dell’interfaccia grafica; eventuali oggetti creati in questo metodo che necessi- tano di una chiusura esplicita (per esempio, le connessioni a database) sono gestiti nel metodo onDestroy; • onStart/onStop: richiamati prima che l’Activity diventi visibile e quando questa viene coperta da altre Activity. La callback onStart è il metodo giusto in cui scri- vere il popolamento dell’interfaccia grafica; • onResume/onPause: la differenza con le callback onStart/onStop è abbastanza sottile; sono richiamati sempre in sequenza tranne nel caso in cui l’Activity venga coperta da un’altra in modo parziale. In questo caso viene richiamato solo onPause e non onStop; quando l’Activity torna in primo piano viene richia- mato solo onResume. In pratica, dopo l’esecuzione di onStart e prima di onStop vi è la certezza che l’Activity sia visibile anche solo parzialmente; dopo onResume e prima di onPause l’Activity è visibile e in primo piano (per questo l’utente può anche interagire con le View contenute). Spesso la distinzione fra queste coppie di callback non è importante e, per questo motivo, non è necessario riscrivere tutti i metodi. Un aspetto del ciclo di vita da tenere presente per non incorrere in errori consiste nel fatto che i metodi onCreate e onDestroy sono invocati una sola volta su un oggetto; tutti gli altri possono essere invocati più di una volta. È infatti abbastanza frequente il caso in cui una Activity venga messa in background e ritorni successivamente in primo piano (per esempio, dopo la pressione del tasto back). Gestione dei metodi di callback comuni a più Activity In alcuni casi può essere utile eseguire del codice in corrispondenza di una callback per ogni Activity presente nell’applicazione; si pensi, per esempio, all’inizializzazione di alcune librerie che permettono di tracciare l’utilizzo da parte degli utenti. Il modo 18
Activity e task in background Capitolo 1 più semplice è ovviamente quello di aggiungere l’invocazione di un metodo dentro ogni callback; può essere utilizzato nel caso in cui il numero di Activity da gestire è basso. Se l’applicazione contiene molte Activity, il copia incolla non è mai la soluzione migliore e porta a codice difficilmente gestibile. Classe base per il codice a comune Una soluzione per evitare il copia incolla è quella che viene comunemente usata nello sviluppo di codice object oriented: è possibile creare una classe base estesa da tutte le Activity in cui fattorizzare il codice a comune. Anche questa soluzione ha comunque delle controindicazioni dovute principalmente all’assenza dell’ereditarietà multipla in Java. Una Activity può estendere una sola classe e quindi la gestione diventa proble- matica nel caso in cui ci sia la necessità di estendere classi diverse (per esempio, Acti- vity e ListActivity). In questi casi, avendo più classi da estendere, sarebbe comunque necessario duplicare il codice a comune. Utilizzo di ActivityLifecycleCallbacks Con la release di Android 4.0 è stata aggiunta l’interfaccia ActivityLifecycleCallbacks all’interno della classe Application. Per sfruttarla è necessario creare una classe che estende Application e registrarla all’interno del manifest. All’interno della callback on- Create della sottoclasse di Application è possibile registrare un oggetto che implemen- ta ActivityLifecycleCallbacks; i metodi contenuti verranno invocati automaticamente in corrispondenza delle callback di ogni Activity. Un esempio di utilizzo è il seguente: @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated( Activity activity, Bundle savedInstanceState) { Log.d(TAG, "Activity created: " + activity.getClass().getSimpleName()); } @Override public void onActivityStarted(Activity activity) { Log.d(TAG, "Activity started: " + activity.getClass().getSimpleName()); } @Override public void onActivityResumed(Activity activity) { Log.d(TAG, "Activity resumed: " + activity.getClass().getSimpleName()); } @Override public void onActivityPaused(Activity activity) { Log.d(TAG, "Activity paused: " + activity.getClass().getSimpleName()); } @Override public void onActivityStopped(Activity activity) { 19
Android | Programmazione avanzata Log.d(TAG, "Activity stopped: " + activity.getClass().getSimpleName()); } @Override public void onActivitySaveInstanceState( Activity activity, Bundle outState) { Log.d(TAG, "State saved: " + activity.getClass().getSimpleName()); } @Override public void onActivityDestroyed(Activity activity) { Log.d(TAG, "Activity destroyed: " + activity.getClass().getSimpleName()); } }); } In questo modo la logica può essere scritta in un posto solo, potendo comunque ge- stire comportamenti diversi in base all’Activity in oggetto sfruttando il parametro pas- sato in ogni metodo. Aspect Oriented Programming L’aspect oriented è un paradigma di programmazione che può essere utilizzato per risolvere problemi complicati sfruttando solo l’object oriented. La teoria che c’è dietro l’aspect oriented è abbastanza complessa e i concetti che la compongono non sono pochi. In questo paragrafo saranno illustrati solo quelli indispensabili per capire come utilizzare l’aspect oriented. Il concetto principale è quello di aspect: rappresenta un aspetto comune a più classi non necessariamente collegate fra loro da una gerarchia. Sfruttando un aspect, è possibile modificare il comportamento delle classi sostituen- do (in parte o completamente) alcune invocazioni di metodi presenti nel bytecode delle classi. Gli esempi classici di aspect sono il logging e la gestione delle transazioni su un database in una applicazione Java enterprise. Un aspect può essere definito in modo concreto sfruttando altri due concetti: • pointcut: rappresentato solitamente da una stringa simile a una regular expres- sion, specifica quando un aspect deve essere applicato. È possibile agire su vari fattori per specificare quali metodi selezionare: oltre al nome del package, della classe o del metodo, è possibile selezionare anche tutte le sottoclassi di una certa classe o tutti i metodi con una specifica annotation; • advice: è il codice da eseguire ogni volta che viene eseguito un metodo compa- tibile con il pointcut corrispondente. Un aspect può essere di tre tipi (è possibile scegliere quale usare in base alle esigenze): • before: l’advice viene eseguito prima del metodo originale; • after: l’advice viene eseguito dopo il metodo originale; è possibile scegliere se eseguirlo sempre oppure solo nel caso di terminazione corretta o con eccezioni; 20
Activity e task in background Capitolo 1 • around: l’advice viene eseguito al posto del metodo originale. All’interno dell’advice è possibile decidere in quali casi eseguire il metodo originale. Per esempio, per loggare tutte le esecuzioni di uno o più metodi è possibile definire un aspect di tipo before; per gestire le transazioni su un database è invece necessario usare un aspect di tipo around. Un altro esempio facilmente implementabile usando l’aspect oriented è la gestione di una cache delle chiamate a un metodo: usando un aspect di tipo around, è possibile accedere ai parametri del metodo originale e al valo- re di ritorno del metodo. Mantenendo in memoria una mappa che associa i parametri al valore di ritorno, è possibile decidere se eseguire il metodo originale o ritornare un valore precedentemente aggiunto nella mappa. La cosa da sottolineare in questi casi è che l’advice è solitamente indipendente dal metodo finale a cui è applicato; per esempio, nel caso di logging, è possibile usare un solo advice per loggare tutti i metodi definiti dal pointcut. Questo è il motivo principale per cui viene utilizzato: permette in modo semplice di scrivere codice a comune fra classi non legate fra loro. L’aspect oriented si basa su una modifica del codice per aggiungere la chiamata all’advice; questa modifica può avvenire in tre momenti diversi: • build time: viene aggiunto uno step nel processo di build per modificare le classi compilate; • load time: le classi sono modificate nel momento in cui sono caricate in memo- ria dal class loader; • runtime: al posto delle classi originali sono utilizzati dei proxy che si occupano di gestire le chiamate agli advice. Esistono varie librerie che permettono di usare l’aspect oriented in Java, ognuna delle quali supporta una o più delle tre modalità appena viste. Per quanto riguarda lo svilup- po su piattaforma Android, la libreria più usata è AspectJ, che funziona aggiungendo uno step nel processo di build. Dopo che il compilatore Java ha creato i file .class, viene lanciato il compilatore AspectJ che si occupa di modificare questi file. Utilizzando il progetto gradle-android-aspectj-plugin (https://github.com/uPhyca/gradle-android- aspectj-plugin), la configurazione del processo di build è banale, basta aggiungere al- cune righe di configurazione nel file di build di Gradle: buildscript { repositories { mavenCentral() } dependencies { classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+' } 21
Android | Programmazione avanzata } apply plugin: 'com.android.application' apply plugin: 'android-aspectj' A questo punto, per definire un aspect è possibile creare una nuova classe contenente le annotation di AspectJ: @Aspect public class LogAspect { @Before("execution(* android.app.Activity+.*(..))") public void logMethod(JoinPoint joinPoint) { Log.d("callbacks", joinPoint.getSignature().getName()); } } Per definire la classe come un aspect è stata utilizzata l’annotation Aspect, il pointcut è definito utilizzando l’annotation Before. In queste poche righe di codice è stato definito un blocco di codice (contenuto all’interno del metodo logMethod) che sarà richiamato prima dell’esecuzione di un qualunque metodo di una sottoclasse di Activity (la regu- lar expression passata all’annotation Before indica questo). Utilizzando il parametro passato al metodo di tipo JoinPoint, è possibile accedere alle informazioni sul metodo originale; da notare che il codice non dipende dalla signature del metodo originale. In questo modo è possibile utilizzare lo stesso advice per gestire metodi di classi diverse con signature differenti. Per provare questa classe è necessario inserirla in un progetto Android opportuna- mente configurato. Mettendo un breakpoint all’interno di un metodo di una Activity e all’interno dell’advice, è possibile verificare che prima viene invocato l’advice e succes- sivamente il metodo originale. Per adesso l’aspect oriented non è molto diffuso all’interno della community di svilup- patori Android; l’utilizzo probabilmente più famoso è all’interno della libreria di logging hugo, sviluppata da Jake Wharton. In questa libreria sono sfruttati due pointcut per identificare i metodi e i costruttori annotati con l’annotation DebugLog. L’advice è tipo around, in quanto ha bisogno di eseguire una parte di codice prima del metodo origi- nale per prendere il timestamp di inizio e dopo il metodo per calcolare la durata. Flusso delle callback del ciclo di vita di una Actvity Sono stati già analizzati i possibili metodi di callback relativi al ciclo di vita di una Activity; in questo paragrafo saranno analizzate le sequenze più comuni in cui queste callback possono essere invocate in base al comportamento dell’utente. Il caso più comune (e anche il più semplice) è quello in cui una Activity viene creata per la prima volta e visualizzata: sono richiamati, nell’ordine, i metodi onCreate, onStart e onResu- me. A questo punto, l’Activity è visibile e l’utente può interagire con essa; le callback 22
Activity e task in background Capitolo 1 richiamate in seguito dipendono dall’interazione dell’utente e da altri eventi esterni all’applicazione gestiti dal sistema operativo (per esempio, una chiamata in arrivo). In particolare, possono esserci tre casi: 1. l’utente preme il tasto back oppure l’Activity termina spontaneamente richia- mando il metodo finish: sono invocati nell’ordine i metodi onPause, onStop e onDe- stroy. A questo punto, l’Activity viene distrutta e il garbage collector di Java può liberare la memoria distruggendo l’oggetto corrispondente; 2. l’Activity viene messa in background in quanto un’altra Activity viene eseguita: questo accade spesso e può verificarsi in diversi casi, per esempio quando l’u- tente preme il tasto Home (anche la home di Android è una Activity), quando viene aperta un’altra Activity della stessa applicazione, oppure quando eventi esterni (come una chiamata in arrivo) causano l’apertura di una nuova Activity. In questi casi viene richiamato il metodo onPause e, solo se l’Activity è coperta totalmente dalla nuova Activity, il metodo onStop; 3. cambio di configurazione del dispositivo: avviene quando c’è un cambio di orientation (portrait o landscape), ma anche in casi meno frequenti, per esem- pio quando viene aperta la tastiera fisica di un dispositivo. In questo caso l’Ac- tivity viene distrutta e viene creata una nuova istanza della stessa Activity. Le callback richiamate sono quelle già viste: onPause, onStop e onDestroy sulla vec- chia Activity e onCreate, onStart e onResume sulla nuova Activity. Gestire i vari casi può non essere semplice; particolare attenzione va posta nel testare il cambio di configurazione, in quanto può avvenire in qualunque momento. In questi casi l’utente si aspetta di ritrovare l’Activity nello stesso stato in cui era in precedenza; il prossimo paragrafo analizzerà questo aspetto. Salvataggio dello stato di una Activity In ogni momento su un dispositivo Android sono in esecuzione più applicazioni, ognu- na delle quali può avere nel proprio stack più Activity aperte. Ogni volta, infatti, che viene aperta una Activity, quella di partenza rimane nello stack in modo da poter es- sere riportata in primo piano nel caso di pressione del tasto back. In caso di necessità di memoria, alcune applicazioni (o alcune Activity di una o più applicazioni) possono essere terminate in automatico dal sistema operativo. Per poter salvare il proprio stato interno è necessario sovrascrivere il metodo onSaveIn- stanceState della classe Activity. Questo metodo ha un parametro di tipo Bundle in cui è possibile salvare tutti gli oggetti da ripristinare in seguito. Il restore dei parametri può avvenire in due metodi che possono essere riscritti in una Activity: 23
Android | Programmazione avanzata • onCreate: il parametro passato a questa callback è un Bundle in cui sono presenti gli oggetti precedentemente salvati. Nel caso si tratti della prima esecuzione, questo parametro ha valore null; • onRestoreInstanceState: callback da riscrivere per eseguire il restore, viene in- vocata in automatico dopo la callback onStart nel caso in cui ci sia uno stato salvato in precedenza. I Bundle sono molto utilizzati nelle classi del framework di Android, per esempio anche il passaggio di parametri a una Activity avviene usando un Intent che internamen- te utilizza un Bundle. Un Bundle può essere visto come una mappa di coppie nome- valore; il nome è sempre una stringa, mentre il valore è un tipo primitivo Java o un oggetto serializzabile. Il concetto di oggetto serializzabile nello sviluppo Android è un po’ diverso da quello standard dello sviluppo Java, infatti comprende anche gli oggetti che implementano l’interfaccia Parcelable oltre a quelli che implementano l’interfaccia Java standard Serializable. L’interfaccia Parcelable è stata introdotta nel framework Android per questioni di per- formance; infatti non fa uso di reflection per leggere e scrivere i valori dei campi di un oggetto, ma delega il tutto a una implementazione che deve essere scritta dallo svilup- patore. La scrittura dei campi avviene nel metodo writeToParcel, mentre la creazione di un oggetto, leggendo i dati salvati in precedenza, avviene nei metodi di un campo statico della classe di tipo Parcelable.Creator. Un esempio di implementazione di una classe con due campi è il seguente: public class Person implements Parcelable { private String name; private String surname; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeString(surname); } protected void readFromParcel(Parcel in) { name = in.readString(); surname = in.readString(); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Person createFromParcel(Parcel in) { Person person = new Person(); 24
Puoi anche leggere