====== Corso di Android ====== ===== Primi passi con Android ===== ==== 1. Introduzione: perché Android ==== Android sta dilagando. Non è più solo questione di smartphone o tablet. Si sta imponendo come sistema operativo in grado di animare qualsiasi dispositivo più o meno mobile tanto da apparire, in prospettiva non troppo futuristica, una presenza sempre più costante nel nostro quotidiano. Gli è stata attribuita -- e probabilmente a ragione -- la più veloce diffusione mai vista per un sistema operativo mobile. Ma quali sono i fattori di questo successo e soprattutto perchè tutto ciò sta capitando ad Android? Le motivazioni ipotizzate sono varie e di varia natura. Gran parte del merito è stato attribuito alle sue **radici ben salde nel mondo open source**. Android, infatti, è figlio di Linux, ha attirato l'interesse di tanti sviluppatori che per anni si sono stretti intorno ai grandi bacini del software libero ed accoglie in sé tutto il meglio di quanto è stato ideato per supportare lo sviluppo del web, desktop e mobile sia in termini di pattern progettuali che di librerie software. Eppure architettura del sistema ed open source sono aspetti che interessano molto una platea fortemente tecnica come programmatori ed ingegneri informatici. Per decretare un successo tanto ampio è necessario che ci sia anche un **forte riscontro di pubblico**. Sicuramente un qualcosa che ha contraddistinto questo sistema è stata la sua adozione da parte di dispositivi molto diversi tra loro, non solo per tipologia -- smartphone piuttosto che tablet -- ma soprattutto per fasce di prezzo, da poche decine di euro fino a cifre piuttosto significative. Ciò ne ha permesso una **diffusione molto diverficata trasversalmente** alle diverse categorie sociali, ma ha causato di riflesso una frammentazione notevole dello scenario applicativo costringendo gli sviluppatori ad una particolare cura degli aspetti di adattamento alle caratteristiche del dispositivo ospite. Proprio in questo, Android ha dimostrato la sua grande modernità offrendo tutto il supporto necessario per permettere all'applicazione in esecuzione di adegursi ad ogni circostanza. **Questa guida è dedicata allo sviluppo di applicativi Android. **Nella prossime lezioni verrà utilizzata una programmazione in linguaggio Java per realizzare applicazioni in cui non manca niente. Si creeranno interfacce utente interattive, dinamiche e graficamente piacevoli. Si avranno gli strumenti per gestire dati e avviare attività di rete in modo che le proprie app prendano da subito parte a quel grande laboratorio di idee che è Internet e tutti i servizi che ne fanno parte. Ed inoltre si avrà a disposizione multimedialità, funzionalità hardware, comunicazione. Per iniziare, Android richiede nozioni di programmazione Java, passione, curiosità e nulla più. Infatti gli strumenti che si renderanno necessari, come si vedrà presto, sono totalmente gratuiti. Quindi non ci sono scuse per non cominciare. ==== 2. L'SDK e l'ambiente di sviluppo ==== Per iniziare a programmare su Android è necessario munirsi innanzitutto dei necessari strumenti software, tutti velocemente reperibili in Internet a costo zero. Necessari sono: * un **JDK**, il kit di sviluppo per la tradizionale programmazione Java, visto che questa è la tecnologia con cui realizzeremo i nostri programmi; * un **IDE** (ambiente di sviluppo integrato) che includa possibilmente tutti gli strumenti necessari al programmatore. Ne verranno presentati due, le alternative più comuni ed entrambe valide: **Eclipse** ed **Android Studio**. Tra gli strumenti appena citati, di cui a breve verranno illustrate le fasi di download ed installazione, non è stato nominato un elemento fondamentale che merita, però, una menzione speciale: l'**Android SDK**. Questo è il vero pacchetto di strumenti che ci permetterà di vedere realizzati i nostri programmi per Android. Nonostante l'importanza fondamentale rivestita, il suo utilizzo, inizialmente, può passare un po' inosservato visto che normalmente viene scaricato insieme agli IDE più comuni, Eclipse e Android Studio. Per questo non mancheremo di sottolinearne sin da ora la sua struttura e le funzionalità che ne fanno parte. Iniziamo, se non o si è già installato, ad insallare Java. È necessario recarsi presso il [[http://www.oracle.com/technetwork/java/javase/downloads/index.html|sito Oracle]] e scaricarne una versione per il proprio sistema operativo, specificando non solo la tipologia -- Windows, Linux, Mac OS o Solaris -- ma anche la versione, 32 o, meglio se se ne ha la possibilità, 64 bit. Una volta eseguito lo scaricamento del pacchetto se ne procede all'installazione che non presenta grandi difficoltà in alcuno dei sistemi per cui è disponibile. Maggiore interesse riveste la **scelta dell'IDE**. Come detto, le due alternative più praticabili al momento sono Eclipse e Android Studio. === Eclipse === **Eclipse** è uno strumento gratuito e molto flessibile, ben noto da tanti anni a varie comunità di sviluppatori. In particolare, la sua natura modulare l'ha reso molto ricco di funzionalità mediante vari plug-in installabili al suo interno oltre che utilizzabile nella programmazione con vari linguaggi, primo tra tutti Java, ma anche C/C++, PHP ed altro ancora. Nel caso di Android è disponibile un bundle ossia un pacchetto completo già dotato degli ADT (Android Developer Tools) e con Android SDK già disponibile. Il link da cui è possibile raggiungerlo è [[https://developer.android.com/sdk/index.html?hl=sk|https://developer.android.com/sdk/index.html]]. La pagina che ci accoglie spiega subito che con un singolo download avremo a disposizione Eclipse, gli ADT e Android SDK già pronti per essere usati. Le versioni disponibili, come per il JDK, si riferiscono ad ogni possibile sistema operativo. Dopo il download -- di un pacchetto piuttosto corposo di circa 500 MB -- è sufficiente procederne alla decompressione. === Android Studio === Un'alternativa giovane (neanche un anno di vita) ma molto promettente è **Android Studio**, sponsorizzato direttamente da Google e pensato appositamente per Android. Si può ottenere dal seguente link [[http://developer.android.com/sdk/installing/studio.html|http://developer.android.com/sdk/installing/studio.html]] e anch'esso è già inclusivo di Android SDK. Nonostante questo interessantissimo strumento non sia ancora arrivato alla versione 1.0 dimostra di accogliere volentieri tutto ciò che di più utile può esserci per lo sviluppatore Android. Gli elementi di Android Studio che spiccano maggiormente sono: * l'utilizzo di Gradle come strumento di build automation, atto quindi ad accompagnare lo sviluppatore nelle fasi di build, sviluppo, test e pubblicazione della propria app; * disponibilità di un gran numero di template per la realizzazione di applicazioni già in linea con i più comuni pattern progettuali; * editor grafico per la realizzazione di layout, molto pratico e dotato di un ottimo strumento di anteprima in grado di mostrare l'aspetto finale dell'interfaccia che si sta realizzando in una molteplicità di configurazioni (tablet e smartphone di vario tipo). === Android SDK === Ultima nota, diamo uno sguardo più ravvicinato all'**Android SDK**. Come detto esso viene già reperito congiuntamente all'installazione di Android Studio o di Eclipse e sarà reperibile, in entrambi i casi, aprendo la cartella contenente l'installazione dell'IDE. Un aspetto molto importante è che questo SDK è costituito da molti strumenti -- programmi, emulatori, piattaforme per ogni versione di Android e molto altro -- la cui composizione non è immutabile ma viene gestita tramite il programma **Android SDK Manager**, avviabile sia da Eclipse che da Android Studio. Grazie al Manager, il programmatore potrà profilare le piattaforme e gli strumenti presenti nel SDK nella maniera più congeniale al proprio lavoro. Maggiori dettagli in merito verranno via via presentati nel corso delle successive sezioni della guida. Un paio di download, qualche click per installare e scompattare: indipendentemente dal sistema operativo del proprio PC, l'ambiente per lo sviluppo su Android non necessità di grandi operazioni per essere pronto all'utilizzo e alla realizzazione della prima app. ==== 3. Alternative allo sviluppo nativo ==== L'approccio alla programmazione Android appare del tutto agevole soprattutto grazie a due aspetti fondamentali già evidenziati: strumenti del tutto gratuiti e semplicità nell'apprestamento dell'ambiente di sviluppo. Ed in effetti è così. A volte però l'appassionato di tecnologia che si avvicina a questo mondo rischia di scoraggiarsi facilmente. Ammesso che si possegga le skill necessarie del linguaggio Java, ci si **accorge presto che un'infarinatura di sintassi spesso non è sufficiente**. Per sfruttare degnamente le possibilità offerte dal framework è necessario essere dei buoni programmatori, consci delle principali problematiche da tenere sott'occhio in uno sviluppo professionale: ottimizzazione delle prestazioni, salvaguardia delle risorse a disposizione e via dicendo. Ma allora che fare se non ci si sente attratti dalla programmazione di questo tipo, cosiddetta //nativa//, e non si vuole comunque rinunciare all'idea di vedere pubblicate le proprie app? Alternative ce ne sono e consistono in strumenti -- comunque validi -- per lo sviluppo **non nativo**, dall'approccio più visuale e spesso familiare a chi proviene dal web design. Eccone alcuni: * [[http://www.html.it/guide/guida-apache-cordova/|Apache Cordova]] e [[http://www.html.it/articoli/apps-mobile-con-steroids-introduzione/|Steroids]] scaturiscono dal know-how nello sviluppo per Internet. In effetti: se CSS ha reso il Web elegante, Javascript gli ha dato vitalità e HTML5 l'ha rivoluzionato, perché non riproporre questi strumenti nello sviluppo mobile? Cordova è la versione open source del progetto PhoneGap e serve a realizzare le cosiddette app ibride con un'interfaccia realizzata in modalità web ma in grado di interfacciarsi con il sistema operativo mobile mediante un vasto numero di API. Steroids nasce per superare alcuni limiti riscontrati in PhoneGap ma senza "reinventare la ruota", si basa infatti su Cordova ma approfondisce il legame con lo strato nativo; * [[http://www.html.it/articoli/creare-app-android-con-corona-sdk/|Corona SDK]] è un ambiente particolarmente versato alla gestione dell'interazione come per i videogiochi. Creato dai Corona Labs non necessità di alcuna conoscenza del linguaggio Java e propone come alternativa lo scripting in LUA, un formalismo dall'approccio molto semplice che permette di personalizzare maggiormente le proprie applicazioni; * [[http://www.html.it/guide/guida-unity-3d/|Unity]] è il più diffuso motore per videogiochi del mondo. Il primato che gli spetta è pienamente meritato in quanto combina editor visuale di altissimo livello ma anche programmazione in tecnologie ad oggetti avanzate come C# oltre che gestione di altri aspetti fondamentali per i videogiochi come grafica, animazione e fisica; * [[http://appinventor.mit.edu/|AppInventor]] è probabilmente la possibilità più abbordabile per l'appassionato di tecnologia a digiuno di programmazione e che desidera qualche risultato piuttosto rapido. E' stato creato dai Google Labs come strumento per la rapida modellazione di app Android ed è stato successivamente ceduto al prestigioso M.I.T.. Intuitività e semplicità le sue chiavi di lettura principali. Nativo sì, nativo no. **Qual è l'approccio** **migliore?** Sicuramente entrambi hanno i loro pro e contro. Mentre da un lato il nativo offre la possibilità di una gestione totale del dispositivo senza la paura di trovare limiti, d'altra parte richiede spesso una programmazione molto professionale e si concentra esclusivamente su una piattaforma impedendo un'agile riciclo dei propri sforzi su altri mercati del mobile. Il non-nativo -- anche se è impossibile generalizzare data la diversità degli ambienti appena citati -- offre vantaggi vari, ascrivibili a volte ad una minore necessità di programmare e molto spesso alla possibilità di creare applicazioni //cross-platform// distribuibili su sistemi operativi diversi. ==== 4. Gli elementi e il funzionamento di base di un'applicazione ==== Ogni applicazione Android, indipendentemente dalla finalità che si prefigge, affida le sue funzionalità a quattro tipi di componenti. Si tratta di **Activity**, **Service**, **Content Provider** e **BroadcastReceiver** ed esistono affinchè la nostra applicazione possa integrarsi alla perfezione nell'ecosistema Android. Prima di addentrarci nella spiegazione di ognuna di esse, è utile concentrarsi un attimo su due principi ispiratori che, tra gli altri, sono alla base della maggior parte delle scelte progettuali operate dai creatori di Android. Tenerli a mente ci permetterà di comprendere meglio ciò che del sistema verrà illustrato nei prossimi capitoli: * **la salvaguardia delle risorse**: essendo progettato per sistemi embedded, storicamente dotati di poche risorse di memoria, Android ha avuto sin da subito uno spirito parsimonioso. Vedremo che, senza far perdere fluidità alla //user-experience,// Android è particolarmente bravo nel distruggere e ricreare parti dell'applicazione in maniera del tutto impercettibile all'utente. Chi dovrà fronteggiare questo atteggiamento sarà il programmatore, ovviamente. Per fortuna, ciò non costerà grandi fatiche ma solo particolare cura nel prendere determinati accorgimenti da applicare con la necessaria consapevolezza. Vale la pena sottolineare che quando si parla di esiguità di risorse in Android, l'obiezione mossa più comunemente ruota attorno alla recente commercializzazione di smartphone che possono contare su 2 GB di memoria RAM. Ciò è vero ma non bisogna dimenticare che Android si propone lo scopo di animare //qualunque// dispositivo in cui riesca a vivere. Il sistema vincerà quindi la sfida di sopravvivenza solo se saprà adattarsi anche a contesti che offrono condizioni molto più disagiate di quelle che può prospettare un nuovissimo device Samsung; * **sicurezza**: Android è figlio di Linux, come già ricordato, quindi ha nel DNA la ricerca della stabilità. Ogni applicazione è un utente a sé stante e vive in un proprio processo in cui viene allocata una nuova istanza della virtual machine, ciò per evitare che il crash di un'applicazione propaghi instabilità alle altre app in esecuzione. Questa forma di "isolamento" viene riflessa anche sulla memoria di massa in quanto ogni applicazione ha un suo spazio in cui lavorare e custodire i propri dati. In merito, **è** **assolutamente sconsigliata, per non dire vietata, qualsiasi pratica che porti un'app ad invadere lo spazio riservato ad un'altra**. Nonostante ciò le nostre applicazioni non sono costrette a vivere in assenza di comunicazione tra loro, anzi Android favorisce un dialogo "sano" tra di esse mettendo a disposizione meccanismi agevoli per la condivisione di contenuti e funzionalità tra componenti del sistema. È arrivato il momento quindi di presentare più da vicino i blocchi costitutivi di un'applicazione. === Le fondamenta di Android === Un'**Activity** è un'interfaccia utente. Ogni volta che si usa un'app generalmente si interagisce con una o più "pagine" mediante le quali si consultano dati o si immettono //input//. Ovviamente la realizzazione di Activity è il punto di partenza di ogni corso di programmazione Android visto che è il componente con cui l'utente ha il contatto più diretto. Un **Service** svolge un ruolo, se vogliamo, opposto all'Activity. Infatti rappresenta un lavoro -- generalemente lungo e continuato -- che viene svolto interamente in background senza bisogno di interazione diretta con l'utente. I Service hanno un'importanza basilare nella programmazione proprio perchè spesso preparano i dati che le activity devono mostrare all'utente permettendo una reattività maggiore nel momento della visualizzazione. Un **Content Provider** nasce con lo scopo della condivisione di dati tra applicazioni. La sua finalità richiama quel principio di sicurezza dell'applicazione di cui si è trattato poco fa. Questi componenti permettono di condividere, nell'ambito del sistema, contenuti custoditi in un database, su file o reperibili mediante accessi in Rete. Tali contenuti potranno essere usati da altre applicazioni senza invadere lo spazio di memoria ma stabilendo quel dialogo "sano" cui si è accennato Un **Broadcast Receiver** è un componente che reagisce ad un invio di messaggi a livello di sistema -- appunto in //broadcast// -- con cui Android notifica l'avvenimento di un determinato evento, ad esempio l'arrivo di un SMS o di una chiamata o sollecita l'esecuzione di azioni. Questi componenti come si può immaginare sono particolarmente utili per la gestione istantanea di determinate circostanze speciali. Molto importante ricordare che una componente può attivarne un'altra mediante apposite invocazioni di sistema. Questa //intenzione// viene codificata con un **Intent** utilizzabile come normale classe Java ma che sottintende un potentissimo strumento di comunicazione di Android. Anche degli Intent faremo uso sin dai prossimi articoli. ==== 5. Il ciclo di vita di un'app Android ==== Android sa che il fattore fondamentale della sopravvivenza di un sistema mobile è la **corretta gestione delle risorse**. Pensiamo ad uno smartphone: è un dispositivo che fa una vita difficile al giorno d'oggi. Non solo si occupa di chiamate ed SMS, ma offre pagine web, giochi, comunicazione sui "social" per molto tempo ogni giorno. Inoltre, capita sempre più spesso che non venga mai spento impedendo così una fase molto comune nella vita dei PC: l'arresto del sistema con conseguente liberazione della memoria e pulizia di risorse temporanee assegnate. Android farà in modo di **tenere in vita ogni processo il più a lungo possibile**. Ciò non toglie che in alcune circostanze ed in base alle risorse hardware a disposizione, il sistema operativo si troverà nella necessità di dover liberare memoria abbattendo processi. Sì ma: quale processo abbattere? La discriminante è quanto un'applicazione, candidata all'eliminazione, sia importante per la **user experience**. Maggiore sarà l'importanza riconosciuta, minori saranno le probabilità che venga arrestata. Così facendo Android tenterà di raggiungere il suo duplice scopo: preservare il sistema e salvaguardare l'utente. I processi possono essere classificati, in ordine di importanza decrescente, come: - **Processi in "foreground"**: sono quelli che interagiscono direttamente o indirettamente con l'utente. Stiamo parlando delle applicazioni che, ad esempio, contengono l'Activity attualmente utilizzata o i Service ad essa collegati. Questi sono i processi che Android tenterà di preservare maggiormente. Importante notare che, comunque, anche le applicazioni in foreground non sono del tutto al sicuro. Se ad esempio il sistema non disponesse di risorse sufficienti a mantenerli tutti in vita, si troverebbe costretto ad arrestarne qualcuno; - **Processi visibili**: non sono importanti come quelli in foreground ma vengono anch'essi grandemente tutelati da Android. Infatti, avendo componenti ancora visibili all'utente anche se non vi interagiscono più, svolgono comunque un ruolo particolarmente critico. Anche in questo caso si tratta di Activity visibili e Service ad esse collegati; - **Processi "service"**: contengono dei service in esecuzione che generalmente svolgono lavori molto utili all'utente anche se non direttamente collegati con ciò che egli vede nel display. Il loro livello di priorità può essere considerato medio: importanti sì ma non tanto quanto i processi di cui ai precedenti due punti; - **Processi in "background"**: contengono activity non più visibili all'utente. Questa è una categoria solitamente molto affollata composta dal gran numero di applicazioni che l'utente ha usato e messo poi in disparte, ad esempio premendo il tasto Home. Non sono considerati molto importanti e sono dei buoni candidati all'eliminazione in caso di scarsità di risorse; - **Processi "empty"**: sono praticamente vuoti nel senso che non hanno alcuna componente di sistema attiva. Vengono conservati solo per motivi di cache, per velocizzare la loro riattivazione qualora si rendesse necessaria. Come ovvio, sono i candidati "numero 1" all'eliminazione da parte del sistema operativo. Quando, nel corso della guida, esamineremo in dettaglio la realizzazione delle varie componenti di sistema -- Activity, Service, ContentProvider e BroadcastReceiver come accennato nel capitolo precedente -- vedremo come l'utente alla luce di quanto appena discusso sarà in grado di comprendere il reale funzionamento delle proprie applicazioni e di come esse vengano gestite dal sistema in ogni circostanza, più o meno favorevole. ==== 6. Hello World: creare un'app Android ==== A questo punto, la filosofia del sistema è stata introdotta, gli strumenti necessari illustrati non resta altro da fare che partire con il primo progetto. Lo scopo di questa lezione non è tanto quello di scrivere un vero e proprio programma quanto quello di farci accompagnare dall'IDE nella creazione di un progetto Android per poterne vedere la struttura, innanzitutto, e mandarlo in esecuzione in modo da verificare la corretta preparazione della nostra macchina di sviluppo. === Prendiamo contatto con l'IDE: creazione di un progetto === Probabilmente il programmatore novizio di Android sarà già più che svezzato nel mondo Java quindi non dovrebbe avere problemi ad orientarsi in Eclipse. Comunque, riepilogando, per poter testare la propria macchina di sviluppo è necessario innanzitutto creare un nuovo progetto Android: * assicuriamoci di avere aperto la Perspective di Eclipse relativa a Java (e non a Java EE né a nessun altro tipo di framework). Per farlo, andiamo sul menu Window ? Open Perspective. Se viene visualizzata la voce Java, selezioniamola; altrimenti possiamo procedere con il punto seguente; * muovendoci nel menu File invochiamo New ? Android Application Project; * seguiamo la procedura di creazione guidata. La serie di schermate (circa 4 o 5) che si susseguono ci chiede di inserire una serie di impostazioni. L'unica assolutamente obbligatoria è il **nome dell'applicazione**. Diciamo che il nome scelto per questa prima applicazione sia -- nemmeno a dirlo -- HelloWorld, **tutte le restanti impostazioni al momento possono essere lasciate con i valori di default**, saranno comunque modificabili successivamente. Si può concludere la creazione del progetto selezionando sempre il pulsante Next finché non diventerà attivo quello denominato Finish. L'**architettura di progetto** così impostata è costituita da un certo numero di file e cartelle. Tutti sono importanti ma gli elementi tra i quali il programmatore dovrà sapersi muovere al più presto con scioltezza sono: * la **cartella src** che conterrà tutto il codice Java che scriveremo; * la **cartella res** in cui risiederanno le cosiddette risorse dell'applicazione per la maggior parte configurate in XML ma non solo; * il file **AndroidManifest.xml** anch'esso in XML che custodirà configurazioni e ruoli dei componenti della nostra app. Un progetto creato in questa maniera da Eclipse è funzionante, sebbene non contenga nessuna funzionalità particolare. Al momento, quindi, non modifichiamo nulla e **passiamo subito al suo avvio immediato**. === Esecuzione del progetto: dispositivo emulato o reale? === Per eseguire il test è necessario che si abbia **a disposizione un dispositivo Android attivo**. Può trattarsi di un dispositivo reale -- tipicamente smartphone o tablet collegato via USB -- o di un sistema emulato (tecnicamente un AVD, Android Virtual Device) mediante gli strumenti messi a disposizione da Android SDK. Partiamo da questo secondo caso. Nel menu Window (attenzione, per vederlo è necessario trovarsi nella prospettiva Java e non Debug) sono disponibili due voci importantissime: //"//**Android SDK Manager**//"// e //"//**Android Virtual Device Manager**//"//. Il primo serve a profilare il nostro SDK richiedendo lo scaricamento di versioni di Android per le quali vogliamo sviluppare o strumenti aggiuntivi come l'utilissimo HAXM di cui si è parlato in un [[http://www.html.it/articoli/migliorare-lemulatore-android-su-architetture-intel/|articolo presente nella sezione Mobile]]. Per il momento la configurazione di un SDK come lo troviamo in un pacchetto Eclipse appena scaricato va benissimo. Il secondo strumento, Android Virtual Device Manager, è ciò che ci serve per **preparare un emulatore**, seguendo questi passi: - cliccare sulla voce Window ? Android Virtual Device Manager; - nell'interfaccia che si apre (vedere in figura) c'è un'area che ospiterà l'elenco degli emulatori che creeremo. Alla sua destra **cliccare il pulsante** ******New.****;** {{:Android:Corso:06_img01-600x591.png?600x591|La prima app Android}} - la nuova finestra che si apre, mostrata in figura, permette di **configurare un dispositivo emulato** semplicemente assegnandogli un nome e la versione di Android che si vuole che esegua oltre ad una serie di impostazioni ulteriori; {{:Android:Corso:06_img02.png?473x715|La prima app Android}} - tornando alla finestra presentata al precedente punto 2. dovremmo vedere il nostro emulatore elencato nell'area bianca. Non resta che **selezionarlo e avviarlo cliccando il pulsante** ******Start.** Se si vuole utilizzare un **dispositivo reale via USB** non è richiesto apportare modifiche in Eclipse. Usando Windows sono solitamente necessari dei driver reperiti direttamente dal sistema operativo o scaricati appositamente dal programmatore. Qualora, al contrario, si usasse Linux non è richiesta l'installazione di alcun driver, macchina di sviluppo e Android si interfacceranno direttamente. === Lancio dell'applicazione === Dopo il boot del sistema emulato, potremo lanciare la nostra applicazione che verrà eseguita direttamente sul dispositivo. Ciò può essere fatto in modalità **Run o Debug** utilizzando uno dei mezzi messi a disposizione dall'IDE (voci nel menu Run, combinazione di tasti o pulsanti sulla barra degli strumenti). Il risultato dell'esecuzione -- visibile in figura -- è molto semplice. {{:Android:Corso:06_img03.png?455x366|06_img03}} Consiste nella sola apparizione della stringa "Hello world!". **Non** **è** **molto ma certifica il raggiungimento dei nostri obiettivi**: la macchina di sviluppo è pronta per mettersi al lavoro e, seconda cosa, l'impianto di progetto che abbiamo ora a disposizione è funzionante e può essere usato come base per sperimentare tutto ciò che impareremo. ===== Il cuore di un'app Android ===== ==== 7. Activity, la "prima pagina" dell'applicazione ==== Il progetto approntato nel capitolo precedente con l'aiuto dell'IDE può essere ora analizzato nel dettaglio. Lo scopo che ci prefiggiamo è quello di osservare da vicino come è fatta un'**Activity**, il primo dei quattro componenti basilari che troviamo nelle applicazioni Android. Nel nostro progetto ce n'è una ed è l'interfaccia utente che mostra il messaggio "Hello World". Nonostante la sua semplicità, mette in luce un aspetto fondamentale. Per creare un'Activity è necessario fare due cose: * **estendere la classe Activity**, appartenente al framework Android; * **registrare l'Activity nell'AndroidManifest.xml** mediante l'uso dell'apposito tag XML . Tra l'altro, questo dettame vale per tutte le quattro componenti fondamentali di un'applicazione. === L'Activity nel codice Java === Il codice Java che realizza l'Activity risiede nella cartella //src//, come spiegato in precedenza. Il contenuto di un tipico "Hello world" potrebbe essere questo: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } La classe si chiama ''MainActivity'' ed estende ''Activity''. Al suo interno viene implementato l'override del metodo ''onCreate''. Per il momento, ci accontentiamo di sapere che questo metodo viene invocato alla creazione dell'Activity. Più avanti scopriremo che si tratta di una tappa fondamentale del ciclo di vita di questo tipo di componenti. A proposito delle due righe di codice presenti all'interno dell'onCreate: * ''super.onCreate(savedInstanceState)'': invoca il metodo omonimo della classe base. Questa operazione è assolutamente obbligatoria; * ''setContentView(R.layout.activity_main)'': specifica quale sarà il "volto" dell'Activity, il suo **layout**. Al momento la dicitura R.layout.activity_main può apparire alquanto misteriosa ma lo sarà ancora per poco, fino al momento in cui verrà illustrato l'uso delle risorse. **Il suo effetto** **è** **quello di imporre come struttura grafica dell'Activity il contenuto del file activity_main.xml presente nella cartella res/layout**. === L'Activity nel file Manifest === Il file AndroidManifest.xml che configura questa applicazione appare così: Il nodo contiene le componenti usate nell'applicazione. In questo caso, c'è un nodo che con l'attributo android:name specifica il nome della classe Java che incarna l'Activity. Se, come in questo caso, non viene specificato un package è sottintesa l'appartenenza della classe al package riportato nel nodo , la //root// del file. Il costrutto intent-filter all'interno serve ad indicare che questa activity è la **main activity del progetto**, in pratica l'interfaccia che accoglierà l'utente all'ingresso nell'applicazione. **E se volessimo altre activity?** È possibile averne? Certamente. L'importante è che ogni activity venga prodotta seguendo i due passi definiti all'inizio di questa sezione: (1) creare una classe Java che estenda Activity e (2) definire un nodo in AndroidManifest.xml che riporti nell'attributo android:name il nome della classe corrispondente. A proposito di questo, il sottonodo intent-filter riferito all'action MAIN va indicato solo nell'Activity principale del progetto. L'utente passerà da un'activity all'altra in maniera simile a come è abituato a fare tra le pagine dei siti Internet ma qui il tutto avverrà mediante il potente meccanismo degli Intent spiegato a breve. ==== 8. Il ciclo di vita di un'Activity ==== Una delle più note illustrazioni della programmazione Android è questa: [{{:Android:Corso:08_img01-600x267.png?600x267|Il ciclo di vita di un'activity in Android}}] La si può trovare sulla documentazione ufficiale, nelle pagine in cui viene spiegato il **ciclo di vita** di un'Activity. Si tratta di una serie di stati attraverso i quali l'esistenza dell'Activity passa. In particolare, nell'illustrazione riportata, gli stati sono rappresentati dalle figure colorate. L'ingresso o l'uscita da uno di questi stati viene notificato con l'invocazione di un metodo di callback da parte del sistema. Il codice inserito in tali metodi dovrà essere allineato con la finalità del metodo stesso affinchè l'app possa essere "un buon cittadino" dell'ecosistema Android. Ad esempio, il primo metodo di callback che viene raffigurato è ''onCreate()'' ed è proprio l'onCreate di cui abbiamo fatto l'override nell'implementazione dell'Activity vista nei capitoli precedenti. Quando un'activity va in esecuzione per interagire direttamente con l'utente vengono obbligatoriamente invocati tre metodi: * **onCreate**: l'activity viene creata. Il programmatore deve assegnare le configurazioni di base e definire quale sarà il layout dell'interfaccia; * **onStart**: l'activity diventa visibile. È il momento in cui si possono attivare funzionalità e servizi che devono offrire informazioni all'utente; * **onResume**: l'activity diventa la destinataria di tutti gli input dell'utente. Android pone a riposo l'activity nel momento in cui l'utente sposta la sua attenzione su un'altra attività del sistema, ad esempio apre un'applicazione diversa, riceve una telefonata o semplicemente -- anche nell'ambito della stessa applicazione -- viene attivata un'altra Activity. Anche questo percorso, passa per tre metodi di callback: * **onPause** (l'inverso di onResume) notifica la cessata interazione dell'utente con l'activity; * **onStop** (contraltare di onStart) segna la fine della visibilità dell'activity; * **onDestroy** (contrapposto a onCreate) segna la distruzione dell'activity. Nel seguito della guida verranno offerti casi pratici di utilizzo ma per il momento ci teniamo su una linea piuttosto teorica. Intanto si consideri che i metodi di callback sono concepiti a coppie (un metodo di avvio con un metodo di arresto: ''onCreate''-''onDestroy'', ''onStart''-''onStop'', ''onResume''-''onPause'') e solitamente il lavoro fatto nel metodo di avvio -- in termini di funzionalità attivate e risorse allocate -- verrà annullato nel corrispondente metodo di arresto. La prima situazione che si mostrerà favorevole ad illustrare l'invocazione dei più importanti metodi di callback sarà l'uso degli Intent per passare da un'activity all'altra. Si tratta, in fin dei conti, di una pratica comunissima nella programmazione Android. ==== 9. Gestire le risorse e gli asset ==== Nelle applicazioni Android il codice Java richiama spesso degli elementi interni al progetto come file XML, stringhe, numeri, immagini ed altro ancora. Il modo migliore per conservare tutti questi "valori" a disposizione dell'applicazione è collocarli all'interno della cartella di progetto denominata //res// e gestirli mediante l'apposito meccanismo delle **risorse**. Il capitolo che inizia si occupa proprio di questo: comprendere bene come gestire le risorse di un'applicazione e come utilizzarle richiamandole nel codice. In conclusione, si vedrà un altro meccanismo di gestione di file all'interno del progetto: gli **assets**. === Dove si trovano le risorse === Se si dà uno sguardo ad un qualsiasi progetto per Android si può vedere che //res// conta diverse sottocartelle i cui nomi non sono affatto casuali. Tra quelle di più comune utilizzo, troviamo: * **layout**: conterrà l'architettura grafica dei componenti dell'interfaccia utente. Sono definiti in XML in una maniera simile a come viene usato HTML per strutturare le pagine web; * **values**: conterrà stringhe, colori, dimensioni e altre tipologie di valori che potranno essere usate in ulteriori risorse o nel codice Java. Importante notare che questi valori costituiranno il contenuto di appositi tag XML ('''', '''', etc.) raggruppati in files dal nome solitamente indicativo: strings.xml, dimens.xml, colors.xml e via dicendo. Tali nomi sono frutto di pura convenzione ma il programmatore può scegliere liberamente come chiamarli; * **drawable**: sono immagini nei formati più comuni o, cosa che può stupire, configurate in XML. === Come richiamare le risorse === Le risorse vengono compilate in un formato binario ed indicizzate mediante un ID univoco. Tali ID sono conservati in una classe Java, di nome ''R'', autogenerata ad ogni modifica e visibile nella cartella //gen// del progetto Android. Abbiamo già incontrato la classe R nell'Activity esaminata in precedenza. Il codice: setContentView(R.layout.activity_main); indicava che il layout dell'activity era collocato tra le risorse. In particolare, ogni percorso interno alla classe R rispecchia una collocazione di risorse nelle sottocartelle di //res// come viene illustrato in figura. {{:Android:Corso:09_img01-600x296.png?600x296|09_img01}} Mediante i loro identificativi, **le risorse sono accessibili sia da codice Java che da altre risorse definite in XML**: * in Java: tramite ''R.tipo_risorsa.nome_risorsa;'' * in XML: ''@tipo_risorsa/nome_risorsa''. Ad esempio, la risorsa di tipo stringa e nome appname: Hello world! potrà essere recuperata, in Java, mediante ''R.string.appname'' o dall'interno di altre risorse XML con ''@string/appname''. === Adattamento multipiattaforma delle applicazioni === La frammentazione dello scenario hardware nel mondo Android resta uno degli scogli più ardui da superare per il programmatore. In questo le risorse giocano un ruolo molto importante. Osservando un tipico progetto Android si può vedere che tra le cartelle interne a res (figura sotto) ne appaiono alcune con nomi "canonici" (menu, values, layout) e altre con nomi "modificati" (drawable-hdpi, drawable-mdpi ma anche values-v14, values-v11, etc.). [{{:Android:Corso:09_img02.png?187x273|}}] Questo perchè al nome della cartella **si può accodare un suffisso che rappresenta la configurazione del dispositivo con cui potranno essere richiamate le risorse contenute**. Se, ad esempio, res/layout conterrà la struttura grafica delle varie interfacce per una qualsiasi configurazione, res/layout-land conterrà layout utilizzabili solo quando il dispositivo è in posizione landscape. Altri modificatori di una certa rilevanza sono quelli che si riferiscono alla lingua del dispositivo: values-it saranno le risorse per dispositivi in italiano, values-en per quelli in inglese. Di modificatori esiste una collezione grandissima, tutta disponibile sulla documentazione ufficiale. Un discorso a parte meritano le immagini. I modificatori applicati alle cartelle drawable (ldpi, mdpi, hdpi e via dicendo) sono alcune delle sigle che identificano le **densità dei display**. Questo concetto di densità rappresenta la quantità di pixel per area fisica dello schermo. Programmando per Android è bene abbandonare l'abitudine di misurare in pixel, utilizzando come unità di misura degli elementi grafici i **dp (Density-Indipendent Pixel)**, una specie di pixel "virtuale" indipendente dalla densità del display che permette di mantenere intatte le proporzioni tra gli elementi del layout al variare delle densità. == Gli assets == La documentazione ufficiale elenca tutte le tipologie di risorse che possono essere usate. Esiste anche un tipo di risorsa "grezza" collocabile nella cartella res/raw. Vi si potrà collocare tutto ciò che non si riesce ad inquadrare in una particolare tipologia. In alternativa alle risorse raw, si possono definire gli **assets**. Questi esulano dal meccanismo delle risorse e vanno depositati nell'omonima cartella di progetto. Non vengono né compilati in formato binario né etichettati con un ID univoco. La loro fruizione da parte dell'applicazione avverrà mediante uno stream che potrà essere richiesto ad una classe Java di nome AssetManager. ==== 10. Intent e messaggi ==== Quando si è parlato delle componenti che rappresentano i blocchi costitutivi di un'app, si è accennato al ruolo degli Intent. Approfondendo il discorso possiamo dire che rappresentano una forma di messaggistica gestita dal sistema operativo con cui **una componente può richiedere l'esecuzione di un'azione da parte di un'altra componente**. Sono uno strumento molto duttile anche se gli utilizzi più comuni ricadono in queste tre casistiche: - avviare un'Activity; - avviare un Service; - inviare un messaggio in broadcast che può essere ricevuto da ogni applicazione. === Gli Extras === Un altro aspetto molto utile degli Intent è che essi, nel recapitare questo messaggio, hanno a disposizione una specie di "bagagliaio", in cui custodiscono dati che possono essere letti dal destinatario. Questi valori condivisi mediante Intent vengono generalmente chiamati Extras e possono essere di varie tipologie, sia appartenenti a classi più comuni che ad altre purchè serializzabili. La gestione degli Extras negli Intent funziona in maniera simile ad una struttura dati a mappa: con dei metodi //put// viene inserito un valore etichettato con una chiave e con i corrispondenti metodi //get// viene prelevato il valore, richiedendolo mediante la chiave di riconoscimento. === L'esempio: un form di login === Prendiamo a titolo di esempio il caso più comune, solitamente utilizzato presto dal programmatore Android neofita, l'attivazione di un'Activity da parte di un'altra. Osserviamo quanto appare in figura: {{:Android:Corso:10_img01-600x279.png?600x279|10_img01}} Abbiamo **due activity**: * **MainActivity** contiene un semplice form di login. Dopo aver inserito username e password viene controllata la validità dei dati ed in caso positivo viene invocata l'apertura di un'altra activtiy; * **SecretActivity** è l'area accessibile solo mediante login e contiene -- immaginiamo -- dati riservati. All'ingresso della seconda Activity, **l'applicazione vuole dare il benvenuto all'utente** ma per farlo ha bisogno di sapere come si chiama. Tutto ciò che serve è già incluso nel meccanismo degli Intent. A livello di codice, nella MainActivity, una volta ottenuto il successo nel login troveremo: Intent i=new Intent(this,SecretActivity.class); i.putExtra("username", account_username); startActivity(i); Le tre operazioni rappresentano: * dichiarazione dell'Intent come normale oggetto Java. In questo caso avremo un cosiddetto **intent esplicito** in quanto appare chiaramente il nome della classe che verrà invocata; * viene inserito, tra gli Extras, una String, la variabile ''account_username'', che sarà trasportata con l'Intent fino a destinazione ossia la classe SecretActivity. Lo scopo è inserire in questa stringa il nome dell'utente che ha effettuato il login. Notare che l'//extra// viene etichettato con una chiave, in questo caso "username". Ciò perchè possono essere trasportati più Extras per ogni Intent e dovrà essere possibile distinguerli per utilizzarli; * infine il metodo ''startActivity'' dimostra quale azione vogliamo attivare con questo Intent, si tratta, in questo caso, dell'avvio di un'Activity. Nel metodo ''onCreate'' della seconda Activity, quella con il contenuto riservato, troveremo le seguenti righe: Intent i=getIntent(); String username=i.getStringExtra("username"); Notiamo subito che l'Activity attivata si trova a disposizione, mediante ''getIntent()'', l'Intent che ne ha provocato l'attivazione. Lo può utilizzare per recuperare la stringa passata, contenente il nome utente. === A livello di ciclo di vita, che succede? === Il passaggio da un'Activity ad un'altra coinvolge i cicli di vita di entrambe. La prima, quella messa a riposo, dovrà passare almeno per ''onPause'' (cessazione interazione con l'utente) e ''onStop'' (activity non più visibile) mentre la seconda percorrerà la catena di creazione ''onCreate''-''onStart''-''onResume''. Ma in che ordine avverrà tutto ciò? La priorità del sistema è **il mantenimento della fluidit****à** **della //user-experience//**. Per questo la //consecutio// delle operazioni sarà: * la **prima Activity passa per onPause** e viene fermata in stato Paused; * la **seconda Activity va in Running** venendo attivata completamente. In tale maniera l'utente potrà usarla al più presto non subendo tempi di ritardo; * a questo punto, mentre l'utente sta già usando la seconda Activity, il sistema può invocare **onStop sulla prima**. ===== L'interfaccia grafica (GUI) ===== ==== 11. Il layout di un'app Android ==== Un'Activity ha bisogno di un volto, di un suo aspetto grafico. Sempre. Anche nei casi più semplici, come quando si limita a stampare la stringa "Hello World!". La struttura grafica di un'Activity prende il nome di **Layout** ed è una delle prime competenze di cui ha bisogno un neo-programmatore Android. Abbiamo già incontrato i layout nel corso di questa guida. È successo quando si è parlato della prima Activity, ma anche quando si è illustrato l'organizzazione delle risorse. Ora è arrivato il momento di entrare nel vivo del discorso scoprendone le tipologie più comuni e analizzandole sia in termini di caratteristiche che di finalità. In Android, comunemente **un layout viene progettato in XML**, in una modalità che ricorda molto l'uso di HTML per le pagine web. Ciò è particolarmente apprezzato da tutti quei programmatori che provengono da esperienze professionali o percorsi didattici nel settore. Gli IDE offrono strumenti visuali per disegnare layout con approccio drag-and-drop e visualizzazioni di anteprima molto utili. Nonostante questi strumenti, nel tempo, siano diventati sempre più usabili ed intuitivi, la conoscenza della sintassi XML per le UI e le corrispondenti classi Java restano un fattore imprescindibile. === Tipi di Layout === Nel framework Android sono stati definiti vari tipi di layout ma ce ne sono tre di utilizzo molto comune che permettono di affrontare ogni situazione: - **LinearLayout**: contiene un insieme di elementi che distribuisce in maniera sequenziale dall'alto verso il basso (se definito con orientamento verticale) o da sinistra a destra (se ha orientamento orizzontale, il valore di default). È un layout molto semplice e piuttosto naturale per i display di smartphone e tablet; - **TableLayout**: altro layout piuttosto semplice, inquadra gli elementi in una tabella e quindi è particolarmente adatto a mostrare strutture regolari suddivise in righe e colonne come form o griglie. È piuttosto semplice da usare e ricorda molto le tabelle HTML nelle pagine web con i ben noti tag
; - **RelativeLayout**: sicuramente il più flessibile e moderno. Adatto a disporre in maniera meno strutturata gli elementi, ricorda un po' il modo di posizionare
flottanti nelle pagine web. Essendo "relative" gli elementi si posizionano in relazione l'uno all'altro o rispetto al loro contenitore, permettendo un layout fluido che si adatta bene a display diversi. Rispetto agli altri due è ricco di attributi XML che servono ad allineare e posizionare gli elementi tra loro. La figura che segue mostra tre semplici esempi realizzati con layout diversi. {{:Android:Corso:11_img01-600x336.png?600x336|I layout di un'app Android}} In generale, non c'è nessun lavoro precluso ad un particolare tipo di layout. Il programmatore imparerà col tempo e la pratica ad associare la struttura grafica che deve realizzare allo strumento più adatto a progettarla. ==== 12. Definire layout in XML, il markup di base ==== Dopo aver classificato i principali layout in base a tipologia e finalità, passiamo all'aspetto pratico, il vero e proprio markup XML necessario a definirli. === Elementi comuni nei layout === Prima di passare agli esempi definiamo alcuni elementi che accomunano le sintassi di tutti i layout. Innanzitutto, gli attributi XML utilizzati per la maggior parte proverranno da un **namespace** avente URI ''http://schemas.android.com/apk/res/android''. Per questo motivo quando definiremo layout in un progetto Android il nodo //root// che conterrà tutti gli elementi mostrerà al suo interno la dichiarazione xmlns:android="http://schemas.android.com/apk/res/android" e darà senso al prefisso android: che verrà usato per tutti gli attributi nel file. Secondo aspetto comune non solo ai layout ma anche a tutti gli elementi in essi contenuti, la presenza obbligatoria di due attributi: **layout_width** e **layout_height**, che definiscono la capacità dell'elemento di estendersi, rispettivamente, in larghezza (width) o altezza (height). Il loro valore può essere una dimensione, espressa in dp, come già spiegato, o una costante da scegliere tra: * **wrap_content**: l'elemento sarà alto o largo a sufficienza per includere il suo contenuto; * **match_parent**: l'elemento si estenderà in altezza o in larghezza fino a toccare il suo contenitore. Quando si andrà ad impostare layout_heigth (o layout_width) l'IDE suggerirà un terzo valore possibile, //fill_parent//. Questo rappresenta un sinonimo di match_parent ma non va usato in quanto ormai deprecato. Nel prosieguo di questo capitolo, verrà presentata la sintassi di base dei principali layout. Gli elementi posizionati all'interno dei layout potranno essere altri layout annidati o widget, termine con cui si indicano tutti i controlli per interfacce utente. Nell'ultimo esempio faranno la loro comparsa TextView e Button, molto comuni nelle UI Android. Una spiegazione più dettagliata dei widget sarà presentata nei prossimi capitoli. === Sintassi dei layout === Il **LinearLayout** riceve con l'attributo **orientation** la sua connotazione principale. Con esso si dichiara in quale senso verranno disposti gli elementi, orizzontalmente (il default) o verticalmente. Un esempio: . . . . . . Il **TableLayout** viene specificato mediante due tag: TableLayout e TableRow. . . . . . . . . . . . . TableLayout rappresenta la tabella nel suo complesso mentre ogni nodo **TableRow contiene tutti gli elementi di una riga**. Il concetto di colonna viene reso in automatico, ogni elemento in un TableRow costituisce una colonna. Il **RelativeLayout** sfrutta gli attributi per definire posizionamenti. Sono molti ma piuttosto intuitivi. A scopo di orientamento, segue una tabella riassuntiva che ne raggruppa le diverse categorie in base alla finalità. Il tipo di valore assegnato a questi attributi può essere booleano (true o false) o l'id di un elemento appartenente al layout. | layout_alignParentTop \\ layout_alignParentBottom \\ layout_alignParentLeft \\ layout_alignParentRight | **Allineamento con il contenitore**: attributi che definiscono se l'elemento deve allinearsi ad uno dei bordi del proprio contenitore. Il valore di questo attributo è di tipo //booleano// | | layout_alignTop \\ layout_alignBottom \\ layout_alignLeft \\ layout_alignRight | **Allineamento con altro elemento**: attributi che definiscono se l'elemento deve allinearsi ad uno dei bordi di un altro elemento del layout. Il valore di questo attributo sarà l'//id dell'elemento// con cui allinearsi | | layout_above \\ layout_below \\ layout_toLeftOf \\ layout_toRightOf | **Posizionamento relativo ad un altro elemento**: indicano se l'elemento si trova, rispettivamente, sopra, sotto, a sinistra o a destra del componente il cui //id// è il valore dell'attributo | | layout_centerHorizontal \\ layout_centerVertical \\ layout_centerInParent | **Centramento**: rispettivamente rappresentano se l'elemento deve essere centrato orizzontalmente, verticalmente o in entrambe le direzioni. Il valore è //booleano//. | Il frammento di XML che segue mostra un esempio di RelativeLayout con una TextView collocata in alto a sinistra ed un Button in basso al centro: