Punto Informatico Libri - Redazione Io Programmo - Android Programming

Document Sample
Punto Informatico Libri - Redazione Io Programmo - Android Programming Powered By Docstoc
					Approfondimenti tematici




      Android
PROGRAMMING

                         Il corso completo per imparare
                      a programmare con il S.O. Google
                               dedicato agli smartphone
Android
programming
Questo approfondimento tematico è pensato per
chi vuol imparare a programmare e creare software
per gli smartphone con sistema operativo Google
Android. La prima parte del testo guida il lettore alla
conoscenza degli strumenti necessari per sviluppare
sulla piattaforma mobile di Mountain View (installa-
zione SDK, librerie e tool di supporto allo sviluppo).
Le sezioni successive sono pensate per un apprendi-
mento pratico basato su esempi di progetto: dialogo
e interazione con l’ambiente operativo del telefo-
nino, interazione con gli utenti, componenti di un
widget, interfacce in XML, gestione del touch, proget-
tazione dei menu e via dicendo.
Una serie di esempi pratici da seguire passo passo
che spingono il lettore a sperimentare sul campo
il proprio livello di apprendimento e lo invitano a
imparare divertendosi.
PROGRAMMARE GOOGLE ANDROID  .  .  .  .  .  .  .  .  .  .  .  .  .  . 4                  e gradevole alla vista. Per questo oggi scopriremo come gestire il
Primo appuntamento alla scoperta di android. installeremo gli                           look delle applicazioni
strumenti di sviluppo necessari e faremo la conoscenza dei principi
di base che regolano il funzionamento del sistema mobile realizzato                     LO STORAGING SECONDO ANDROID  .  .  .  .  .  .  .  .  .  .  .  .  . 57
da google                                                                               Leggere e scrivere file dal disco di uno smartphone android è
                                                                                        un’operazione possibile ma soggetta a restrizioni di sicurezza e a
LE RISORSE ESTERNE IN GOOGLE ANDROID  .  .  .  .  .  .  . 12                            norme di buon uso. Oggi impareremo come utilizzare correttamente
In questo secondo articolo impareremo a manipolare le risorse                           il file system di android
esterne. Scopriremo che android rende facile l’utilizzo di tutto
quello che, pur non essendo codice, è indispensabile al corretto                        DATABASEDA TASCHINO  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 61
funzionamento di un’applicazione                                                        Una delle caratteristiche più interessanti di android è il dbms
                                                                                        integrato nel sistema, che dota le applicazioni della capacità
COME IL SISTEMA GESTISCE LE ATTIVITÀ  .  .  .  .  .  .  .  .  . 16                      di archiviare e ricercare velocemente i dati. in questo articolo
Terzo appuntamento. Le “attività” sono il componente software più                       impareremo come approfittarne
utilizzato dai programmatori android. in questo articolo impareremo
cos’è un’attività, come viene gestita dal sistema e come possiamo                       GESTIONE DEI CONTENT PROVIDER  .  .  .  .  .  .  .  .  .  .  .  .  .  . 67
realizzarne di nostre                                                                   I content provider costituiscono la maniera di android per
                                                                                        condividere dati fra le applicazioni. in questo articolo impareremo a
INTERFACCE: LAYOUT E COMPONENTI .  .  .  .  .  .  .  .  .  .  .  . 21                   consultare i provider predefiniti e vedremo anche come costruire un
Quarto appuntamento. inizia la trattazione dei concetti e degli                         fornitore di contenuti custom
strumenti di android per la costruzione e la gestione delle interfacce
utente. si comincia con i widget ed i layout di base, indispensabili in                 LE APPLICAZIONI GIRANO IN PARALLELO  .  .  .  .  .  .  .  .  . 71
ogni applicazione                                                                       I servizi sono quella funzionalità di android che permette di
                                                                                        eseguire operazioni in sottofondo, anche quando l’applicazione che
INTERFACCE IN XML PER ANDROID  .  .  .  .  .  .  .  .  .  .  .  .  .  . 26              le ha avviate non è più attiva. Insomma: multitasking allo stato
Quinto appuntamento. vi è sembrato che il design java di                                puro, anche in mobilità!
un’interfaccia utente, in android, sia lungo e noioso? nessun
problema! oggi impareremo a servirci dell’xml per velocizzare e                         TU SEI QUI! TE LO DICE ANDROID  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 75
semplificare l’operazione                                                               I servizi location-based sono una delle caratteristiche più attraenti
                                                                                        di android. impariamo a realizzare applicazioni in grado di
GESTIRE IL TOUCH SU ANDROID  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 31          localizzare l’utente via gps e di disegnare la sua posizione in una
Sesto appuntamento. in questa puntata del corso impareremo                              mappa
le varie tecniche per intercettare le azioni di tocco e digitazione
eseguite dall’utente sui widget presenti nel display, in modo da                        APP ANDROID FACILI CON APP INVENTOR  .  .  .  .  .  .  .  . 81
reagire di conseguenza                                                                  App Inventor è il nuovo sistema di google per creare
                                                                                        applicazioni android senza scrivere una sola riga di codice.
ANDROID: TUTTO SUI MENU  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 36     scopriamo in cosa consiste e utilizziamolo per realizzare
Settimo appuntamento. argomento del mese sono i menu. le                                facilmente le nostre idee
applicazioni android ne supportano diversi tipi, che l’utente può
sfruttare per azionare comandi e impostare le opzioni. conosciamoli                     PORTA TWITTER SU GOOGLE ANDROID .  .  .  .  .  .  .  .  .  .  . 88
e impariamo a programmarli                                                              In questo articolo vedremo come sviluppare un’applicazione
                                                                                        per android, capace di dialogare con il servizio di Social
NOTIFICHE E FINESTRE DI DIALOGO  .  .  .  .  .  .  .  .  .  .  .  .  .  . 41            Networking Twitter. A tal scopo mostreremo come utilizzare
Ottavo appuntamento. questo mese incrementeremo l’interattività                         la libreria Twitter4j
delle nostre applicazioni, dotandole della possibilità di emettere
degli avvisi e di interrogare l’utente attraverso le finestre di dialogo                UN CLIENT TWITTER SU ANDROID  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 93
                                                                                        Continuiamo e completiamo il nostro progetto per implementare un
INFO E FOTO: COSÌ LE PRESENTI MEGLIO!  .  .  .  .  .  .  .  .  . 47                     client Twitter sulla piattaforma Android. L’occasione ci permetterà di
Nono appuntamento. ci occuperemo dei widget in grado di leggere                         approfondire molti aspetti sul funzionamento del sistema operativo
le informazioni da organizzare e mostrare all’utente. scopriremo                        creato da Google
i componenti utilizzati per realizzare liste, tabelle e gallerie di
immagini                                                                                ANDROID DIALOGA CON OUTLOOK  .  .  .  .  .  .  .  .  .  .  .  .  . 98
                                                                                        Il paradigma del “data on the cloud” risulta comodo quando si
UN’APPLICAZIONE CON STILE  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 52   vogliono gestire le stesse informazioni da diversi client, eterogenei
Il design è uno dei fattori più importanti in ambito mobile. non è                      tra loro. In questo articolo lo adopereremo per tenere sincronizzate
sufficiente che un’applicazione funzioni: deve anche essere elegante                    delle note tra android e outlook
                          Android programming Gli strumenti necessari per imparare a programmare Android
                          COVER STORY �               Gli strumenti necessari per imparare a programmare Android




PROGRAMMARE
GOOGLE ANDROID
PRIMO APPUNTAMENTO ALLA SCOPERTA DI ANDROID. INSTALLEREMO GLI STRUMENTI
DI SVILUPPO NECESSARI E FAREMO LA CONOSCENZA DEI PRINCIPI DI BASE CHE REGOLANO
IL FUNZIONAMENTO DEL SISTEMA MOBILE REALIZZATO DA GOOGLE




                                           M
                                                      eno di due anni fa Google ha rilasciato
                                                      una versione preliminare del kit di svi-
                                                      luppo di Android, il suo nuovo SO
                                           dedicato agli smartphone. Futurologi e semplici
                                           appassionati si divisero immediatamente tra
                                           entusiasti e scettici. I detrattori, in particolar
                                           modo, hanno sempre visto in Android un esperi-
                                           mento, e non qualcosa di reale al quale i produt-
    ❑ CD ❑ WEB                             tori di dispositivi avrebbero creduto. A loro favo-
    corsoandroid1.zip
                                           re ha deposto il fatto che, per un periodo piutto-
                    cdrom.ioprogrammo.it
                                           sto lungo, nessuno smartphone equipaggiato
                                           con Android ha fatto capolino sul mercato, ben-
                                           ché il sistema e i suoi strumenti di sviluppo fos-
                                           sero ormai disponibili da parecchio tempo. La          Fig. 1: L’architettura di Google Android
                                           tecnica di Google, in realtà, era ed è ancora quel-
                                           la di sempre: far venire l’acquolina in bocca (e far
                                           parlare di sé) con versioni preliminari dei suoi
                                           software e dei suoi servizi.                           COME È FATTO
                                           Nel caso di Android, molti sviluppatori sono           ANDROID
                                           stati fidelizzati e fatti appassionare a un siste-     Android, essendo un sistema operativo di
                                           ma che, allora, non era ancora sul mercato.            moderna fattura, è abbastanza complesso.
                                           Nel frattempo le cose sono cambiate: Android           Anche se il suo target sono i dispositivi mobi-
                                           è stato consolidato, e molti produttori di             li, l’architettura di Android ha poco da invi-
                                           dispositivi mobili hanno aderito o stanno ade-         diare a quelle dei comuni sistemi per desktop
                                           rendo all’alleanza capeggiata da Google.               o laptop. Tale architettura è presentata sche-
                                           Grazie alle strategie di Google, esiste già una        maticamente in Fig.1.
                                           comunità molto ampia di sviluppatori, estre-           Come si evince dalla figura, Google ha attinto
                                           mamente produttiva, che altri sistemi mobili           a piene mani dal mondo Open Source.
                                           non possono vantare. Migliaia di applicazioni          Il cuore di ogni sistema Android, tanto per
                                           sono state già sviluppate, e molte altre lo            cominciare, è un kernel Linux, versione 2.6.
                                           saranno nei prossimi tempi.                            Direttamente nel kernel sono inseriti i driver
                                           Il sistema appare inoltre stabile ed offre             per il controllo dell’hardware del dispositivo:
               REQUISITI
                                           potenzialità molto ampie. Per questo motivo,           driver per la tastiera, lo schermo, il touchpad,
                                           a partire dal numero che state leggendo,               il Wi-Fi, il Bluetooth, il controllo dell’audio e
Conoscenze richieste
   Basi di Java                            ioProgrammo dedicherà ad Android un corso              così via. Sopra il kernel poggiano le librerie
                                           di programmazione a puntate.                           fondamentali, anche queste tutte mutuate dal
Software                                   Si comincia, naturalmente, con lo studio del-          mondo Open Source. Da citare sono senz’al-
    Java SDK (JDK) 5+,
    Eclipse 3.3                            l’architettura del sistema, l’installazione e          tro OpenGL, per la grafica, SQLite, per la
                                           l’utilizzo degli strumenti di sviluppo, un             gestione dei dati, e WebKit, per la visualizza-
Impegno                                    primo compendio sui principi di base della             zione delle pagine Web. Insomma, nei prossi-
¥                                          programmazione Android e lo sviluppo di una            mi mesi avremo di che discutere!
Tempo di realizzazione                     prima semplice applicazione del tipo “Ciao             L’architettura prevede poi una macchina vir-
                                           Mondo”.                                                tuale e una libreria fondamentale che, insie-

                                                                                                                            h t t p : / / w w w. i o p r o g r a m m o . i t
     G 14 /Ottobre 2009
     4                                                                                                                                  And roi d pr o g r am m in g
      Gli strumenti necessari per imparare a programmare
     Gli strumenti necessari per imparare a programmare Android Android Android programming
                                                                           � COVER STORY


me, costituiscono la piattaforma di sviluppo         to i requisiti, è possibile procedere. Prendete
per le applicazioni Android. Questa macchina         l’archivio ZIP scaricato da Internet e scompat-
virtuale si chiama Dalvik, e sostanzialmente è       tatelo dove meglio preferite. È tutto: l’Android
una Java Virtual Machine. Come verifichere-          SDK è già pronto all’uso! Al massimo si può
mo più tardi, alcune delle caratteristiche di        perfezionare l’installazione aggiungendo alla
Dalvik e della sua libreria non permettono di        variabile d’ambiente PATH del sistema opera-
identificare immediatamente la piattaforma           tivo il percorso della cartella tools che è all’in-
Java disponibile in Android con una di quelle        terno dell’Android SDK. Così facendo sarà più
di riferimento (Java SE, Java ME).                   semplice invocare gli eseguibili del kit da riga
Nel penultimo strato dell’architettura è possi-      di comando. L’operazione, ad ogni modo, non
bile rintracciare i gestori e le applicazioni di     è indispensabile per un corretto funziona-
base del sistema. Ci sono gestori per le risor-      mento del kit. In questo corso, inoltre, cerche-
se, per le applicazioni installate, per le telefo-   remo di servirci il meno possibile della riga di
nate, il file system e altro ancora: tutti compo-    comando, anche se in alcune occasioni tor-
nenti di cui difficilmente si può fare a meno.       nerà utile se non indispensabile.
Infine, sullo strato più alto dell’architettura,
poggiano gli applicativi destinati all’utente
finale. Molti, naturalmente, sono già inclusi
con l’installazione di base: il browser ed il        ADT PER ECLIPSE
player multimediale sono dei facili esempi.          Benché Android SDK disponga di script che au-
A questo livello si inseriranno anche le appli-      tomatizzano l’installazione delle applicazioni,
cazioni che, insieme, impareremo a sviluppa-         il lancio dell’emulatore e il debug del codice,
re nell’arco di questo corso a puntate.              lavorare in un ambiente integrato, con ogni op-
                                                     zione a portata di clic, è sicuramente più facile.
                                                     Specie quando l’ambiente integrato si chiama Ecli-
                                                     pse. Nel sito di Android contattato in prece-
ANDROID SDK                                          denza è disponibile anche un plug-in per la ce-
Per sviluppare applicazioni in grado di girare       lebre piattaforma di sviluppo Open Source. Que-
su sistemi Android, è necessario installare sul      sto add-on si chiama Android Development Tools
proprio PC un apposito kit di sviluppo (SDK),        for Eclipse, che abbreviato diventa ADT.
che sia completo di emulatore, librerie e            Il modulo, al momento della stesura di questo ar-
documentazione. Se avete già sviluppato per          ticolo, funziona con le più recenti versioni di
piattaforme quali Java ME o Windows Mobile,
capite bene cosa intendiamo (ma se non
l’avete mai fatto, non vi preoccupate: qui si
spiega tutto). La prima buona notizia è che
l’Android SDK è disponibile gratuitamente e
senza discriminazioni per sistemi Windows,
Linux e MacOS X. Come inizio, non c’è male.
È possibile scaricarlo collegandosi all’indiriz-
zo: http://developer.android.com/sdk/
Vi verrà proposto di scaricare la più recente
versione disponibile. Procedete pure al down-
load del pacchetto adatto al vostro sistema.
Al momento della stesura di questo articolo,
la versione scaricabile dalla pagina è la 1.5_r3
(che sta per 1.5 Release 3), ma se ne trovate di
più recenti fate pure: non dovrebbero differire
troppo da quella presa qui a riferimento.
L’installazione del kit è veramente semplice.
L’unica cosa di cui bisogna accertarsi, prima
di procedere, è di soddisfare i requisiti di base.
In particolare, è richiesto che il sistema
disponga già di un Java SDK (JDK) versione 5
o successiva. È strettamente indispensabile
soddisfare questo requisito, poiché Android si
programma in Java, e senza un JDK non è pos-         Fig. 2: Configurando la nuova fonte in Eclipse, è possibile scaricare ed installare
sibile compilare il codice. Dopo aver verifica-      automaticamente il plug-in per lo sviluppo del software Android (Eclipse 3.5)


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                         Ottobre 2009/ 15 G
                                                                                                                         5
        Android programming Gli strumenti necessari per imparare a programmare Android
        COVER STORY �               Gli strumenti necessari per imparare a programmare Android


                 Eclipse, che sono la 3.3, la 3.4 e anche la nuova         equipaggiato con Android. Per sviluppare le
                 3.5. Può essere installato direttamente dall’in-          applicazioni, quindi, dobbiamo imparare a
                 terno della piattaforma di sviluppo.                      interagire con questo emulatore. Il primo
                 Avviate Eclipse ed eseguite il wizard per                 concetto che si deve assimilare è quello che
                 l’installazione di nuovi componenti. In Eclipse           ha nome Android Virtual Device (AVD), cioè
                 3.5 lo si fa con la voce di menu “Help » Install          dispositivo virtuale Android. Nel nostro PC
                 New Software”. Nella 3.4 la voce di menu è “Help          possiamo creare e configurare quanti disposi-
                 » Software Updates”, e poi si deve selezionare la         tivi virtuali vogliamo. È come avere tanti diffe-
                 scheda “Available software”. In Eclipse 3.3, infine,      renti smartphone da utilizzare per i propri
                 la voce di menu da richiamare è “Help » Softwa-           test, solo che invece di dispositivi di plastica e
                 re Updates » Find and install”, scegliendo poi            silicio si tratta di macchine virtuali, fatte cioè
                 “Search for new features to install”. Giunti a de-        di puro software, da eseguire attraverso
                 stinazione, scegliete l’opzione per aggiungere            l’emulatore. In questo modo è anche possibi-
                 un nuovo sito remoto alla lista delle fonti pre-          le avviare contemporaneamente sullo stesso
                 sentate dal wizard (pulsante “Add”). L’indirizzo          PC due o più dispositivi virtuali, ad esempio
                 da specificare è:                                         per testare un’applicazione che fa interagire
                 https://dl-ssl.google.com/android/eclipse/r               più smartphone, come una chat o un gioco
                 A questo punto selezionate la voce corrispondente         multiplayer. Impariamo allora a gestire
                 alla nuova fonte e procedete attraverso i singo-          l’elenco dei dispositivi virtuali configurati nel
                 li passi del wizard. Il plug-in per lo sviluppo del       nostro Android SDK. È possibile gestirli da
                 software Android sarà automaticamente scari-              riga di comando, usando il comando android
                 cato e installato. Dopo il riavvio di Eclipse, recatevi   che è nella cartella tools del kit di sviluppo, ma
                 immediatamente nella schermata delle preferenze           l’uso dell’interfaccia di gestione resa disponi-
                 dell’ambiente (voce di menu “Window » Prefe-              bile da ADT in Eclipse ci renderà l’operazione
                 rences”). Qui troverete disponibile la nuova ca-          senz’altro più agevole. Attivate la voce di
                 tegoria “Android”, nell’elenco sulla sinistra.            menu “Window » Android AVD Manager”.
                 Selezionatela e impostate il percorso del vostro
                 Android SDK: è necessario affinché Eclipse pos-
                 sa agganciare il kit di sviluppo. Durante questa
                 fase dovreste anche ricevere un pop-up per
                 l’accettadella licenza del plug-in.




                                                                           Fig. 4: La maschera di gestione dei dispositivi virtuali
                                                                           Android



                                                                           La finestra presenta la lista dei dispositivi vir-
                                                                           tuali configurati (inizialmente vuota) e la
                 Fig. 3: Affinché il plug-in funzioni correttamente        maschera per la creazione di una nuova istan-
                 è necessario fornire il percorso dell’Android SDK         za. Sfruttiamo questa possibilità e creiamo il
                                                                           nostro primo AVD. Le voci da compilare sono:

                 Per ora è possibile tralasciare le altre possibili        •   Name: il nome che si vuole attribuire al
                 impostazioni collegate al plug-in: imparere-                  dispositivo virtuale, ad esempio “Android1”.
                 mo ad usarle più avanti, quando avremo                    •   Target: la tipologia del dispositivo. Sceglia
                 preso più confidenza con l’ambiente.                          mo Android 1.5. Creeremo così un disposi
                                                                               tivo virtuale compatibile con la versione 1.5
                                                                               delle specifiche di Android.
                                                                           •   SD Card: qui è possibile dotare il dispositi
                 GESTIONE DEGLI AVD                                            vo virtuale di una scheda di memoria vir-
                 Il kit di sviluppo comprende un emulatore che                 tuale. È possibile specificare sia il percorso
                 ci consentirà di provare le nostre creazioni sul              di un file di immagine di una scheda di me
                 PC, prima di installarle su un reale dispositivo              moria, se si vuole riutilizzare una memoria


G 16 /Ottobre 2009
                                                                                                      h t t p : / / w w w. i o p r o g r a m m o . i t
6                                                                                                                 And roi d pr o g r am m in g
      Gli strumenti necessari per imparare a programmare
     Gli strumenti necessari per imparare a programmare Android Android Android programming
                                                                           � COVER STORY


      virtuale esi stente, sia una dimensione di        sistema per un’interazione di più basso livello
      spazio, per creare una nuova memoria              con il dispositivo.
      virtuale. Percorriamo quest’ultima strada e
      specifi chiamo il valore “64M”. Verrà così
      creata una scheda di memoria virtuale di 64
      MB.
•     Skin: dall’elenco è possibile scegliere la riso
      luzione del dispositivo. Le scelte possibili
      sono HVGA-P (equivalente a 480x320),HV
      GA-L (320x480), QVGA-P (320x240) e QVGA-
      L (240x320). C’è poi una scelta di default
      chiamata semplicemente HVGA, che corri
      sponde comunque a HVGA-P. Lascia mola
      selezionata.

Dopo aver impostato questi valori, confer-
miamo l’operazione con il tasto “Create AVD”.
Il nuovo dispositivo virtuale entrerà a far             Fig. 5: Configurazione dell’emulatore di Android
parte dell’elenco gestito dal manager, e da ora
potrà essere utilizzato per eseguire il debug e
il test delle applicazioni.
                                                        CIAO, MONDO ANDROIDE!
                                                        È venuto il momento di utilizzare ADT e
                                                        l’emulatore per programmare la nostra prima
PROVIAMO L’EMULATORE                                    applicazione Android.
Se non siete pratici nell’utilizzo di Android,          Naturalmente sarà una variante del classico
prima di iniziare a programmare è meglio che            “Ciao, Mondo!”.
ci prendiate confidenza. Esplorando le appli-           Avviate Eclipse. Grazie ad ADT disponete ora
cazioni di base potrete così entrare nell’ottica        di una nuova categoria di progetto, chiamata
del sistema, per imparare i principi di funzio-         “Android Project”. Create un progetto di que-
namento e di design delle sue applicazioni.             sto tipo.Nel wizard di creazione del progetto
Potete avviare un dispositivo virtuale dall’e-          utilizzate la configurazione che viene riporta-
sterno di Eclipse, al solo scopo di fare un “giro       ta di seguito:
di ricognizione. Con il prompt dei comandi              • Project name: CiaoMondoAndroide
posizionatevi nella directory tools del kit di          • Build target: selezioniamo “Android 1.5”.
sviluppo. Lanciate ora un comando del tipo:             • Application name: Ciao Mondo
emulator @NomeAVD                                       • Package name: it.ioprogrammo.helloandroid
A “NomeAVD” dovete sostituire il nome che,              • CreateActivity: CiaoMondoAndroideActivity
nel corso del paragrafo precedente, avete
assegnato al dispositivo virtuale creato.
Ad esempio: emulator @Android1
Qualche istante di pazienza (al primo lancio
anche qualcosa in più) e l’emulatore cari-
cherà e renderà disponibile il dispositivo vir-
tuale Android, in tutto il suo splendore. Con il
mouse è possibile simulare il touchpad del
dispositivo, cliccando sullo schermo. Fatevi
un giro e prendete pure confidenza con
l’ambiente. Come prima cosa divertitevi con
le applicazioni di base, come il browser o la
rubrica: vi aiuteranno molto nel comprendere
i principi di utilizzo del sistema. Poi passate a
del materiale più tecnico: il menu principale
contiene la voce “Dev Tools”, che raccoglie
una serie di strumenti dedicati a chi Android
vuole programmarlo, e non solo farci un giro
di prova. Tra questi spicca l’emulatore di ter-
minale, che permette di avere una shell di              Fig. 6: Il nuovo tipo di progetto “Android Project” è ora disponibile in Eclipse


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                             Ottobre 2009/ 17 G
                                                                                                                             7
                   Android programming Gli strumenti necessari per imparare a programmare Android
                   COVER STORY �               Gli strumenti necessari per imparare a programmare Android


                                 Il progetto, a questo punto, può essere creato, azio-
                                 nando il tasto “Finish”.




                                                                                           Fig. 8: Eclipse mette a disposizione l’opzione di avvio
                                                                                           “Android Application”



                                                                                           automaticamente a installare al suo interno
                                                                                           l’applicazione “CiaoMondoAndroide”, per poi
                                                                                           avviarla non appena l’operazione sarà com-
                                                                                           pletata. È fatta: il vostro primo software per
                                                                                           Android sta girando davanti ai vostri occhi.
                                                                                           Successivamente, accedendo alle configurazioni
          NOTA                                                                             di esecuzione (voce di menu “Run » Run Config
                                                                                           urations” in Eclipse 3.5 e 3.4, “Run » Open Run
      OPEN HANDSET                                                                         Dialog” in Eclipse 3.3), sarà possibile alterare i
          ALLIANCE                                                                         parametri di avvio dell’emulatore e dell’applica-
   Per essere precisi, dietro
   Android non c’è soltanto                                                                zione. Tra questi, anche il dispositivo virtuale sul
         Google. Il colosso di                                                             quale sarà installato e avviato il software.
  Mountain View ha fatto la      Fig. 7: Wizard di creazione di un nuovo
 prima mossa e di sicuro è       “Android Project” di Eclipse
   l’attore di maggior peso,
      tuttavia l’evoluzione di
     Android è curata da un
      consorzio denominato       Eclipse popolerà automaticamente il progetto, in-
Open Handset Alliance. Del       serendo le librerie di Android e la struttura di base
     gruppo, oltre a Google,     dei progetti per questa piattaforma. In uno slan-
 fanno parte numerosi altri      cio di generosità, Eclipse provvederà anche alla          Fig. 9: L’applicazione “Ciao Mondo”, eseguita
  nomi interessanti, tra cui                                                               dall’emulatore
   HTC (la prima a produrre      creazione della prima classe della soluzione, chia-
dispositivi equipaggiati con     mata CiaoMondoAndroideActivity (come specifi-
   Android), Intel, Motorola,    cato alla voce “Create Activity”) e inserita nel pac-
 Samsung, LG e molti altri.      chetto it.ioprogrammo.hello android (come alla            Vi consigliamo di fare qualche esperimento.
  C’è anche Telecom Italia.      voce “Package name”). Aprite il codice della classe       Provate, ad esempio, a creare differenti AVD, col-
           Per approfondire:
     http://www.openhan          e modificatelo alla seguente maniera:                     laudando così il software con schermi di diffe-
         dsetalliance.com/                                                                 renti dimensioni e proporzioni. Un altro esperi-
                                 package it.ioprogrammo.helloandroid;                      mento interessante, che vi consiglio di compiere
                                 import android.app.Activity;                              prima di procedere oltre, è l’utilizzo del debugger
                                 import android.os.Bundle;                                 di Eclipse con l’applicazione Android. Ponete un
                                 import android.widget.TextView;                           breakpoint sulla classe realizzata e avviate di
                                 public class CiaoMondoAndroideActivity extends Activity   nuovo emulatore ed applicazione, questa volta in
                                 {                                                         modalità debug.
                                 @Override public void onCreate(Bundle save
                                 dInstanceState) {super.onCreate(savedInstanceState);
                                     TextView tv = new TextView(this);
                                     tv.setText("Ciao, Mondo Androide!");                  DALVIK E LE
                                     setContentView(tv);                                   LIBRERIE ANDROID
                                 }                                                         Superata la prova del primo progetto Android,
                                 }                                                         torniamo ad occuparci dei concetti fondamen-
                                                                                           tali per la programmazione in questo ambien-
                                 Ora selezionate la radice del progetto                    te. Come abbiamo appreso e dimostrato, la piat-
                                 “CiaoMondoAndroide”, attivate il menu con-                taforma di sviluppo è di natura Java. Tuttavia si
                                 testuale da tasto destro e lanciate la voce “Run          tratta di una piattaforma particolare e perso-
                                 As » Android Application”.                                nalizzata, che vale la pena approfondire.
                                 L’emulatore verrà caricato. Eclipse provvederà            La macchina virtuale, chiamata Dalvik, sembra

                                                                                                                       h t t p : / / w w w. i o p r o g r a m m o . i t
   G 18 /Ottobre 2009
   8                                                                                                                               And roi d pr o g r am m in g
      Gli strumenti necessari per imparare a programmare
     Gli strumenti necessari per imparare a programmare Android Android Android programming
                                                                           � COVER STORY


essere una Java Virtual Machine, ma in realtà         PRINCIPI
non lo è del tutto. Ci spieghiamo meglio: una         DI PROGRAMMAZIONE
Java Virtual Machine esegue del codice byteco-        Chi programma con Java ME sa che le MIDlet
de, giusto? Ecco, la Dalvik Virtual Machine non       sono il mattone fondamentale delle applicazioni
esegue bytecode standard, ma un altro lin-            MIDP; chi crea applicazioni Web con Java EE non
guaggio, chiamato DEX (Dalvik EXecutable),            può ignorare cosa sia una Servlet; persino i pro-
studiato appositamente per una migliore resa          grammatori meno esperti sanno che le applica-
in uno smartphone. Con l’Android SDK ed Ecli-         zioni Java, per girare in un browser, devono esse-
pse, ad ogni modo, ci sembrerà di utilizzare una      re inglobate in una Applet.
regolare Java Virtual Machine. L’ambiente di          Tutto questo per dire che ciascun ambiente, Java
sviluppo, infatti, provvede automaticamente           e non, dispone dei suoi mattoni fondamentali,
alla generazione del codice DEX, ri-compilan-         che lo sviluppatore può estendere e implementa-
do il bytecode che a sua volta è frutto di una pri-   re per trovare un punto di aggancio con la piat-
ma comune compilazione Java. Per noi sarà tut-        taforma.
to trasparente. Questa peculiarità di Dalvik,         Android non sfugge alla regola, anzi la amplifica.
quindi, non influenzerà il nostro modo di pro-        A seconda di quel che si intende fare è disponibi-
grammare. La stessa considerazione, invece,           le un diverso modello. Android fornisce quattro
non può essere fatta riguardo la libreria di base     mattoni di base:
che affianca Dalvik. Aprite il documento al per-
corso docs/reference/packages.html, nel vostro        •   Attività
Android SDK. È l’indice dei package Java com-             Le attività sono quei blocchi di un’applica-
presi nella libreria di base.                             zione che interagiscono con l’utente utiliz-
Scorretela velocemente e traete pure le prime             zando lo schermo e i dispositivi di input                    NOTA
conclusioni. C’è parecchio della Standard Edi-            messi a disposizione dallo smartphone.
tion di Java, ma non c’è tutto.                           Comunemente fanno uso di componenti UI            SITO
Ad esempio non ci sono AWT e Swing.                       già pronti, come quelli presenti nel pac-         DI RIFERIMENTO
                                                                                                            Il principale sito Web di
I pacchetti fondamentali, però, ci sono tutti, ed         chetto android.widget, ma questa non è ne-        riferimento per tutti gli
appaiono in larga misura identici a come li vuo-          cessariamente la regola. La classe dimo-          sviluppatori Android del
le Sun. Davvero poco viene dalla Micro Edition,           strativa CiaoMondoAndroideActivity è un’at-       mondo è, naturalmente,
praticamente nulla.                                       tività. Le attività sono probabilmente il mo-     quello ufficiale,
La piattaforma Java ME è stata snobbata da An-            dello più diffuso in Android, e si realizzano     raggiungibile all’indirizzo:
                                                                                                            http://developer.
droid, che le ha preferito una libreria più simi-         estendendo la classe base android.app.Activity.   android.com/
le a quella di un sistema desktop. Non passano
poi inosservati i tanti package con prefisso an-      •   Servizio
droid che, naturalmente, sono esclusivi di que-           Un servizio gira in sottofondo e non intera-
sta speciale piattaforma. Servono per l’interazione       gisce direttamente con l’utente.                             NOTA
diretta con le funzionalità del sistema sotto-            Ad esempio può riprodurre un brano MP3,
stante. Ad esempio: il package android.widget con-        mentre l’utente utilizza delle attività per fa-   DOCUMENTAZIONE
tiene i componenti custom di Android per la               re altro. Un servizio si realizza estendendo la   Tantissima
                                                                                                            documentazione (soltanto
costruzione delle interfacce grafiche (in Ciao-           classe android.app.Service.                       in inglese, però) è messa a
MondoAndroide abbiamo usato TextView); nel                                                                  disposizione nella cartella
pacchetto android.graphics ci sono le funzioni        •   Broadcast Receiver                                docs dell’Android SDK.
primitive per la grafica di più basso livello; in         Un Broadcast Receiver viene utilizzato quan-
android.location ci sono gli strumenti per inte-          do si intende intercettare un particolare
ragire con un eventuale ricevitore GPS com-               evento, attraverso tutto il sistema. Ad esem-
preso nel dispositivo.                                    pio lo si può utilizzare se si desidera com-
Ciascuno dei pacchetti Android, naturalmen-               piere un’azione quando si scatta una foto o
te, meriterebbe una trattazione estesa e com-             quando parte la segnalazione di batteria sca-
pleta, tanti sono i possibili campi di applica-           rica. La classe da estendere è android. con-
zione. Ne emerge il profilo di una piattaforma di         tent.BroadcastReceiver.
sviluppo complessa, perché molto ricca, ma
semplice, perché ordinata e perché condivide          •   Content Provider
parecchio con l’edizione tradizionale di Java.            I Content Provider sono utilizzati per espor-
Il consiglio, naturalmente, è quello di tenere            re dati e informazioni. Costituiscono un ca-
sempre a portata di mano la documentazione del-           nale di comunicazione tra le differenti ap-
le API di Android. Fatevi poi guidare dalla cu-           plicazioni installate nel sistema. Si può crea-
riosità: date pure una prima occhiata alle clas-          re un Content Provider estendendo la clas-
si che più stuzzicano la vostra fantasia.                 se astratta android.content.ContentProvider.

h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                    Ottobre 2009/ 19 G
                                                                                                                    9
                   Android programming Gli strumenti necessari per imparare a programmare Android
                   COVER STORY �               Gli strumenti necessari per imparare a programmare Android


                                 Un’applicazione Android è costituita da uno o                <category android:name="
                                 più di questi elementi. Molto frequentemente,                                android.intent.category.LAUNCHER" />
                                 contiene almeno un’attività, ma non è detto                  </intent-filter>
                                 che debba sempre essere così.                               </activity>
                                                                                             </application>
                                                                                             <uses-sdk android:minSdkVersion="3" />
                                                                                             </manifest>
                                 I PACCHETTI APK
                                 Le applicazioni Android sono distribuite sotto              È il manifesto descrittore citato poco fa. Al suo
                                 forma di file APK (Android Package). Al loro in-            interno potete e dovete dichiarare i componenti
                                 terno vengono raccolti gli eseguibili in formato            del vostro software. Eclipse, all’atto di creazio-
                                 DEX, le eventuali risorse associate e una serie             ne del progetto, ha già eseguito su di esso alcu-
                                 di descrittori che delineano il contenuto del               ne configurazioni iniziali.
                                 pacchetto. In particolare, nel cosiddetto mani-             Ad esempio ha registrato l’attività CiaoMon-
                                 festo, vengono dichiarate le attività, i servizi, i         doAndroideActivity, ha specificato le proprietà
                                 provider e i receiver compresi nel pacchetto, in            generali dell’applicazione e ha anche generato
           NOTA
                                 modo che il sistema possa agganciarli e azio-               e impostato un’icona per il nostro programma
                                 narli correttamente.                                        (res/drawable /icon.png). Ovviamente queste
           IL TOOL ADB           Torniamo, in Eclipse, sul progetto CiaoMon-                 scelte possono essere alterate, e nuovi compo-
       Oltre all’emulatore, la
  cartella tools dell’Android    doAndroide. Al suo interno troverete un file chia-          nenti possono essere aggiunti al progetto.
      SDK contiene un altro      mato AndroidManifest.xml, fatto come segue:                 Con lo speciale editor visuale messo a disposi-
            strumento molto                                                                  zione da Eclipse, vi risulterà tutto molto sem-
     interessante, chiamato      <?xml version="1.0" encoding="utf-8"?>                      plice: è sufficiente fare un po’ di pratica e ap-
   adb. Si utilizza da riga di                         <manifest xmlns:android="http://      profondire di volta in volta l’aspetto d’interesse.
comando. Lanciatelo senza
      parametri, e avrete un                       schemas.android.com/apk/res/android"      Una volta che il lavoro è stato completato, è
  veloce aiuto in linea sulle     package="it.ioprogrammo.helloandroid"                      possibile esportare il file APK da distribuire ai
        funzionalità messe a      android:versionCode="1"                                    fortunati possessori di un sistema Android.
disposizione. In particolare,     android:versionName="1.0">                                 Prima di distribuire in giro il pacchetto è però
    mentre l’emulatore è in                                                                  necessario apporre su di esso una firma digi-
 esecuzione, i comandi adb
       install e adb uninstall    <application android:icon="@drawable/icon" an              tale. In caso contrario, Android non potrà
   possono essere utilizzati                           droid:label="@string/app_name">       installarne i contenuti.
  per installare e rimuovere      <activity android:name=".CiaoMondoAndroi                   Questo è l’unico vincolo imposto dal sistema.
applicazioni dal dispositivo,                                                  deActivity"   Il fatto che un pacchetto debba essere firmato
          mentre lo speciale       android:label="@string/app_name">                         non deve preoccupare lo sviluppatore: non è
          comando adb shell
permette di aprire una shell     <intent-filter>                                             necessario che una certification authority
         sul sistema Android      <action android:name="android.intent.                      riconosca la chiave utilizzata per la firma.
                     emulato.                                             action.MAIN" />    Di conseguenza è possibile firmare un pac-
                                                                                             chetto APK anche servendosi di un certificato
                                                                                             “fatto in casa”. In parole semplici: non bisogna
                                                                                             pagare nessuno perché i nostri software siano
                                                                                             autorizzati, possiamo fare tutto da noi.
                                                                                             In Eclipse, ancora una volta, è questione di un
                                                                                             clic: aprite il menu contestuale sulla radice
                                                                                             del progetto (tasto destro del mouse, in
                                                                                             Windows) e selezionate la voce “Android Tools
                                                                                             » Export Signed Application Package”.
                                                                                             Al secondo step del wizard di generazione del
                                                                                             pacchetto, vi verrà chiesto da dove prelevare
                                                                                             la firma digitale.
                                                                                             Solitamente gli oggetti di questo tipo vengono
                                                                                             raccolti e conservati all’interno di un keysto-
                                                                                             re. In un keystore, cioè, ci sono più firme digi-
                                                                                             tali. Se non avete mai formato un keystore in
                                                                                             precedenza, o se semplicemente ne volete ini-
                                                                                             ziare uno nuovo, selezionate l’opzione “Create
                                                                                             new keystore”.
Fig. 10: Lo speciale editor messo a disposizione da Eclipse per il file                      Il keystore verrà conservato all’interno di un
AndroidManifest.xml                                                                          file, il cui percorso va obbligatoriamente spe-

                                                                                                                       h t t p : / / w w w. i o p r o g r a m m o . i t
   G 20 /Ottobre 2009
   10                                                                                                                               And roi d pr o g r am m in g
      Gli strumenti necessari per imparare a programmare
     Gli strumenti necessari per imparare a programmare Android Android Android programming
                                                                           � COVER STORY




Fig. 11: La prima schermata di generazione
di un pacchetto APK firmato a partire dal progetto
CiaoMondoAndroide


                                                        Fig. 13: La maschera per la creazione di un nuova firma
cificato. Scegliete dove riporre il keystore (nel       digitale
caso in Fig.13, la directory è C:\keystores) e
date un nome a vostro piacimento a file
(android_keystore, nel caso in immagine).
Non c’è bisogno di usare un’estensione parti-           COSA TRATTEREMO
colare per il nome del file. È invece buona pra-        NEI PROSSIMI ARTICOLI
tica proteggere i propri keystore con una pas-          DEL CORSO                                                                 L’AUTORE
sword, in modo che le nostre firme digitali             Nel prossimo numero della rivista andremo un
                                                                                                                       Carlo Pelliccia lavora
                                                        po’ più al di dentro della faccenda, approfon-
                                                                                                                       presso 4IT (www.4it.it),
                                                        dendo i principi di programmazione di Google                   dove si occupa di analisi e
                                                        Android, conoscendo più intimamente la strut-                  sviluppo software per
                                                        tura delle sue applicazioni e iniziando la rasse-              piattaforme Java. Nella sua
                                                        gna delle API messe a disposizione dal sistema                 carriera di technical writer
                                                                                                                       ha pubblicato cinque
                                                        operativo. Per tutto l’arco di questo corso si cer-
                                                                                                                       manuali ed oltre
                                                        cherà sempre di rimanere “con i piedi per terra”,              centocinquanta articoli,
                                                        affrontando i differenti argomenti in maniera                  molti dei quali proprio tra le
                                                        sistematica e concludendo sempre le lezioni                    pagine di ioProgrammo. Il
                                                        con un esempio pratico e funzionale, in modo                   suo sito, che ospita anche
                                                                                                                       diversi progetti Java Open
                                                        da fornire ai lettori un’immediata implemen-
                                                                                                                       Source, è disponibile
                                                        tazione dei concetti appresi.                                  all’indirizzo
                                                                                                                       www.sauronsoftware.it
Fig. 12: La creazione di un nuovo keystore                                                       Carlo Pelliccia


non possano essere utilizzate nel caso in cui
qualcuno ci rubi il file. Pertanto abbiate cura
di impostare una password sufficientemente
sicura.
Visto che il keystore appena creato è vuoto, il
passo successivo del wizard ci fa creare una
chiave, cioè una firma digitale. Dobbiamo
inserire il nome della chiave (detto alias), la
password per l’utilizzo della chiave, una vali-
dità in anni (di solito si usa il valore 25) e i dati
anagrafici di base del firmatario (nome e
cognome).
Superata la fase di creazione o selezione del
keystore e della chiave, il wizard fa scegliere
dove salvare il pacchetto APK che sarà genera-
to. Scegliete la destinazione e concludete
l’operazione.
È fatta: il pacchetto è stato generato e firmato.
Potete ora installarlo su un dispositivo
Android reale, in plastica, metallo e silicio.          Fig. 14: La selezione del file su cui sarà salvato il pacchetto APK


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                             Ottobre 2009/ 21 11
                                                                                                                             G
                                                        La gestione delle nei programmi Android
                              Android programming La gestione delle risorserisorse nei programmi Android
                                   MOBILE �




LE RISORSE ESTERNE
IN GOOGLE ANDROID
IN QUESTO SECONDO ARTICOLO IMPAREREMO A MANIPOLARE LE RISORSE ESTERNE.
SCOPRIREMO CHE ANDROID RENDE FACILE L’UTILIZZO DI TUTTO QUELLO CHE, PUR NON
ESSENDO CODICE, È INDISPENSABILE AL CORRETTO FUNZIONAMENTO DI UN’APPLICAZIONE




                                            S
                                                  e c’è un aspetto di Android dal quale si
                                                  evince la modernità di questo sistema, è la
                                                  sua maniera di gestire le risorse e i dati.
                                            Nelle piattaforme di sviluppo meno moderne,
                                            spesso e volentieri, le risorse esterne come i dati
                                            di configurazione, i messaggi di interfaccia, le
                                            immagini o altro materiale simile, sono trattate
                                            senza alcun riguardo speciale. Android, invece,
    ❑ CD ❑ WEB                              richiede che i progetti siano organizzati in una
    Android144.zip
                                            certa maniera. La corretta gestione delle risorse
                     cdrom.ioprogrammo.it
                                            in questa piattaforma, è importante tanto quan-
                                            to la stesura del codice. In un certo senso, con
                                            Android non si può imparare a programmare se
                                            prima non si apprende come organizzare e
                                            richiamare le risorse. Perciò, dedichiamo all’ar-
                                            gomento questo secondo articolo del corso.




                                            LA STRUTTURA                                             Fig. 1: La struttura, in Eclipse, di un progetto Android
                                            DEI PROGETTI ANDROID                                     appena creato
                                            Avviamo Eclipse e torniamo sul progetto Ciao
                                            MondoAndroide, realizzato il mese scorso per
                                            dimostrare le funzionalità di base del kit di svilup-    speciale struttura predefinita, formata dalle tre
                                            po per Android. Quando abbiamo creato il proget-         sotto-directory drawable, layout e values. La prima,
                                            to, Eclipse ha predisposto per noi un albero di car-     drawable, serve per le immagini utilizzate dal
                                            telle, all’interno del quale sono stati generati auto-   software, mentre layout e values ospitano dei spe-
                                            maticamente diversi file. Guardate la Fig.1, che         ciali file XML utili per definire in maniera dichiara-
                                            mostra la situazione del file system all’atto di crea-   tiva l’aspetto dell’applicazione e i valori utilizzati al
                                            zione del progetto.                                      suo interno. Oltre a src, assets e res c’è infine la car-
                                            Tra i file generati automaticamente c’è Android-         tella gen, che contiene la speciale classe chiamata
              REQUISITI
                                            Manifest.xml, cioè il descrittore dell’applicazione,     R, probabile abbreviazione di Resources. Invocando
                                            che già abbiamo iniziato a conoscere. Torneremo          questa classe, infatti, è possibile richiamare via
Conoscenze richieste
   Java                                     ad approfondirlo mano a mano che gli argomenti           codice le risorse memorizzate sotto la directory res.
                                            trattati ce ne daranno occasione. Oltre al descritto-    Impareremo oggi stesso come farlo. Sappiate
Software                                    re c’è il file default.properties, poco rilevante per    comunque che la classe R viene generata automa-
    Java SDK (JDK) 5+,
    Eclipse 3.3+                            noi, poiché serve esclusivamente al sistema di           ticamente dal sistema e non deve mai essere modi-
                                            build automatico. Ci sono poi delle directory: src,      ficata a mano.
                                            assets, res e gen. La prima, src, è quella dove dob-
                                            biamo andare a realizzare i package e le classi della
Impegno
                                            nostra applicazione. Le cartelle res e assets servono
¥                                           per ospitare le risorse esterne necessarie all’appli-    GESTIONE DEI VALORI
Tempo di realizzazione
                                            cazione, come le immagini, i file audio e altro anco-    Il primo tipo di risorse che impareremo a mani-
                                            ra. La cartella res, in particolar modo, gode di una     polare sono i valori. Si tratta di coppie chiave-

                                                                                                                                h t t p : / / w w w. i o p r o g r a m m o . i t
     G 58 / Novembre 2009
     12                                                                                                                                     And roi d pr o g r am m in g
                        La gestione delle nei programmi Android
                  La gestione delle risorse risorse nei programmi Android Android programming
                                                                             � MOBILE


valore dichiarate all’interno dei file XML che            <item>Carlo</item>
sono al percorso di progetto res/values. Eclipse,         <item>Claudia</item>
per default, crea a questo percorso il file               <item>Nami</item>
strings.xml, pensato per raccogliere le stringhe         </string-array>
usate dall’applicazione che sarà sviluppata.           • Stili e temi, con il tag <style>. Servono per
Ad ogni modo potete rinominare il file o aggiun-         creare degli stili di disegno ed impaginazione,
gerne quanti altri ne volete, al fine di categoriz-      un po’ come fanno i fogli di stile CSS nel caso di
zare al meglio i valori necessari alla vostra appli-     HTML. Dentro il tag <style> vanno inseriti dei
cazione. L’importante è che tutti i file presenti        tag <item> con le singole voci che compongo-
nella cartella values seguano il seguente modello:       no lo stile. Gli stili possono essere applicati alle
                                                         interfacce grafiche. Di certo ne riparleremo più
<?xml version="1.0" encoding="utf-8"?>                   avanti. Eccovi comunque un esempio:
<resources>                                              <style name="titolo">
   <!-- valori qui -->                                    <item name="android:textSize">18sp</item>
</resources>                                            <item name="android:textColor">#000088</item>
                                                         </style>                                                         NOTA
All’interno del tag <resources> … </resources> è
possibile dichiarare differenti tipi di valori.        Usando Eclipse, comunque, non c’è bisogno di             DIFFERENZA TRA
Supponiamo di voler dichiarare un valore di tipo       imparare l’elenco a memoria: qualsiasi file XML          RES E ASSETS
                                                                                                                La differenza tra le cartelle
stringa chiamato nome e con contenuto Carlo:           posto sotto la directory res/values viene automati-      res e assets è poco
                                                       camente lavorato con un apposito editor.                 evidente, eppure c’è.
<?xml version="1.0" encoding="utf-8"?>                                                                          La directory res è pensata
<resources>                                                                                                     per gestire le risorse in
                <string name="nome">Carlo</string>
                                                                                                                maniera struttura, ed infatti
                                                                                                                è suddivisa in sottocartelle.
</resources>
                                                                                                                Tutte le risorse posizionate
                                                                                                                in res vengono prese in
Ci sono numerosi tipi di dati supportati. Ecco un                                                               esame dal sistema di build
elenco completo:                                                                                                e riferite nella speciale
                                                                                                                classe R. Quelle dentro res,
                                                                                                                dunque, sono delle risorse
• Stringhe, con il tag <string>.                                                                                gestite. Sotto assets,
• Colori, con il tag <color> e con valori espressi                                                              invece, è possibile
  in forma esadecimale secondo i modelli                                                                        depositare qualsiasi file si
  #RRGGBB o #AARRGGBB (AA sta per il canale            Fig. 2: L’editor di Eclipse gestisce i file XML          desideri senza che il
  alpha, che regola la trasparenza del colore). Ad                                                              sistema di build esegua
                                                                                                                un’analisi preventiva e crei
  esempio: <color name="rosso">#FF0000</color>                                                                  il riferimento in R.
• Misure e dimensioni, con il tag <dimen> e con                                                                 Le risorse esterne
  valori numerici decimali accompagnati da un’u-       RICHIAMARE                                               conservate nella directory
  nità di misura che può essere px (pixel), in (pol-   LE RISORSE DA XML                                        assets possono essere
  lici), mm (millimetri), pt (punti a risoluzione      Come scritto in apertura, la modernità di                caricate servendosi della
                                                                                                                classe android.content.res.
  72dpi), dp (pixel indipendenti dalla densità) e sp   Android può essere evinta proprio dalla sua              AssetManager. Nella
  (pixel indipendenti dalla scala). Ad esempio:        maniera di gestire le risorse. Le piattaforme di         maggior parte dei casi,
  <dimen name="lato">180px</dimen>                     una volta non concedevano sistemi agevolati,             comunque, non c’è bisogno
• Rettangoli di colore, con il tag <drawable>.         finendo così per favorire l’accoppiamento fra            di ricorrere alla cartella
  I valori possibili sono colori esadecimali come      codice e dati. Tuttora non è raro vedere dei sor-        assets, poiché res offre una
                                                                                                                maniera semplificata e
  nel caso del tag <color>. Ad esempio:                genti in Java, in C o in qualsiasi altro linguaggio,     completa per l’accesso alle
  <drawable name="verde">#00FF00</drawable>            con valori e messaggi digitati direttamente den-         risorse.
• Array di interi, con il tag <integer-array>.         tro il codice. Questa pratica non è corretta ed è
  Gli elementi dell’array vanno espressi con più       sconsigliata da ogni manuale: è sempre meglio
  occorrenze del tag annidato <item>.                  separare i dati dal codice, perché in questa
  Ad esempio:                                          maniera il software è più facile sia da realizzare
  <integer-array name="numeriPrimi">                   sia da mantenere. Android intende favorire la
   <item>2</item><item>3</item>                        pratica del disaccoppiamento fra dati e codice, e
   <item>5</item><item>7</item>                        lo fa attraverso gli strumenti che stiamo pren-
  </integer-array>                                     dendo in considerazione oggi. I valori dichiarati
• Array di stringhe, con il tag <string-array>.        nei file XML sotto values, così come tutte le altre
  Anche in questo caso si usa il tag <item>.           risorse della cartella res e delle sue annidate, sono
  Ad esempio:                                          trattati dal sistema in maniera speciale.
  <string-array name="nomi">                           Il kit di sviluppo, infatti, fornisce delle agevola-

h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                          Novembre 2009 / 59 13
                                                                                                                            G
                                                La gestione delle nei programmi Android
                      Android programming La gestione delle risorserisorse nei programmi Android
                           MOBILE �


                                    zioni per richiamare le risorse dalle varie parti      • @color, per i colori.
                                    del software. Sostanzialmente un’applicazione          • @dimen, per le dimensioni.
                                    Android è costituita da file dichiarativi XML e da     • @drawable, per i valori drawable, ma anche
                                    classi Java. Sia in un caso sia nell’altro, ci sono      per le immagini messe in res/drawable.
                                    scorciatoie per richiamare le risorse incluse in       • @layout, per richiamare i layout presenti nella
                                    res. Cominciamo dal caso XML e prendiamo a               cartella res/layout.
                                    riferimento il più importante dei file di questo       • @raw, per i file nella cartella res/raw (cfr. box
                                    tipo: AndroidManifest.xml. Quando, al suo inter-         laterale).
                                    no, si dichiarano i dettagli dell’applicazione, è      • @string, per le stringhe.
                                    possibile scrivere qualcosa come:                      • @style, per gli stili.

                                    <?xml version="1.0" encoding="utf-8"?>                 Con @drawable, in particolar modo, è possibile
            NOTA
                                    <manifest xmlns:android=                               riferire sia i valori dichiarati con i tag <drawable>
                                           "http://schemas.android.com/apk/res/android"    in res/values, sia le immagini conservate nella car-
              ANIM, RAW                  package="mypackage"                               tella res/drawable. Ad esempio, se in res/drawable
                  E XML
   Oltre a drawable, layout e            android:versionCode="1"                           viene messa un’icona chiamata icon.png, sarà
            values, che Eclipse          android:versionName="1.0">                        possibile richiamarla con la formula @draw-
 introduce automaticamente             <application android:label="LaMiaApplicazione">     able/icon. Ad esempio lo si può fare in Android
    in ogni nuovo progetto, la            ...                                              Manifest.xml, per associare l’icona all’applicazio-
      cartella res può ospitare
                                       </application>                                      ne:
      anche le sotto-directory
  anim, raw e xml. In anim si       </manifest>
   inseriscono le animazioni,                                                              <?xml version="1.0" encoding="utf-8"?>
           che possono essere       Il nome dell’applicazione, cioè LaMiaAp-               <manifest xmlns:android=
     programmate in maniera         plicazione, è stato in questo caso digitato diretta-          "http://schemas.android.com/apk/res/android"
          dichiarativa con uno
                                    mente dentro il codice XML. Con Android questo              package="mypackage"
speciale formato XML; sotto
       raw è possibile inserire     è corretto, tuttavia si può fare di meglio. Si può          android:versionCode="1"
          qualsiasi tipo file, ad   includere il titolo dell’applicazione nel file              android:versionName="1.0">
         esempio un audio da        res/values/strings.xml, alla seguente maniera:            <application
          riprodurre all’interno                                                                      android:label="@string/app_name"
  dell’applicazione; in xml un
                                    <?xml version="1.0" encoding="utf-8"?>                            android:icon="@drawable/icon">
        qualsiasi file XML, che
           Android provvederà       <resources>                                                                ...
            automaticamente a          <string                                                </application>
decodificare. Ne riparleremo             name="app_name">LaMiaApplicazione</string>        </manifest>
             nei prossimi mesi.     </resources>


                                    A questo punto il descrittore dell’applicazione
            NOTA
                                    può essere riscritto come segue:                       RICHIAMARE
                                                                                           LE RISORSE DA JAVA
                                    <?xml version="1.0" encoding="utf-8"?>                 Valori e risorse possono essere richiamati da
  DISTINGUERE I FILE                <manifest xmlns:android=                               codice Java servendosi della classe android.con-
        CON I VALORI                       "http://schemas.android.com/apk/res/android"    tent.res.Resources. Stando all’interno di una atti-
  Benché, teoricamente, sia
         possibile mettere in            package="mypackage"                               vità, cioè di una classe che estende android.
res/values un solo file XML              android:versionCode="1"                           app.Activity, è sufficiente richiamare il metodo
     con ogni tipo di valore             android:versionName="1.0">                        getResources() per ottenere il punto d’accesso alle
    possibile, le linee guida          <application android:label="@string/app_name">      risorse dell’applicazione: Resources res =
     dello sviluppo Android            </application>                                      getResources(); Una volta ottenuto l’oggetto, è
 consigliano di distinguere i
      file per topic, cioè per      </manifest>                                            possibile invocare su di esso la seguente serie di
 argomento. Solitamente si                                                                 metodi:
  consiglia di raccogliere le       Anziché scrivere “LaMiaApplicazione”, si è usato
            stringhe in un file     il riferimento @string/app_name. Questa scorcia-       • public int getColor(int id)
    strings.xml, i colori (e i      toia, come intuibile, viene sostituita dalla risorsa     Restituisce il colore avente l’identificativo di
 drawable) in colors.xml, le
dimensioni in dimens.xml e          di tipo stringa con nome app_name, che nel file          risorsa specificato.
        gli stili in styles.xml.    strings.xml abbiamo dichiarato essere proprio          • public float getDimension(int id)
                                    “LaMiaApplicazione”.                                     Restituisce la dimensione avente l’identificati-
                                    La regola generale per richiamare una risorsa in         vo di risorsa specificato.
                                    un file XML, quindi, è basata sul modello:             • public Drawable getDrawable(int id)
                                    @tipo/nome. I tipi validi sono:                          Restituisce l’oggetto disegnabile avente l’iden-
                                    • @array, per gli array.                                 tificativo di risorsa specificato.


    G 60 / Novembre 2009
                                                                                                                     h t t p : / / w w w. i o p r o g r a m m o . i t
    14                                                                                                                           And roi d pr o g r am m in g
                        La gestione delle nei programmi Android
                  La gestione delle risorse risorse nei programmi Android Android programming
                                                                             � MOBILE


• public int[] getIntArray(int id)                         <manifest xmlns:android=
  Restituisce l’array di interi avente l’identificati-            "http://schemas.android.com/apk/res/android"
  vo di risorsa specificato.                                    package="it.ioprogrammo.testresources"
• public String getString(int id)                               android:versionCode="1"
  Restituisce la stringa avente l’identificativo di             android:versionName="1.0">
  risorsa specificato.                                         <application android:icon="@drawable/icon"
• public String[] getStringArray(int id)                                    android:label="@string/app_name">
  Restituisce l’array di stringhe avente l’identifi-             <activity android:name=".TestResourcesActivity"
  cativo di risorsa specificato.                                         android:label="@string/app_name">                     NOTA
                                                                    <intent-filter>
Tutti questi metodi agganciano la risorsa desidera-                    <action
                                                                                                                   INTERNAZIONALIZ-
ta attraverso un identificativo numerico (int id). Ma             android:name="android.intent.action.MAIN" />     ZAZIONE
come fare a conoscere gli ID associati alle risorse e                  <category android:name=                     Se si punta ad un mercato
ai valori inseriti nella cartella res? Semplice: attra-                  "android.intent.category.LAUNCHER" />     internazionale, è bene che
verso la speciale classe autogenerata R! Al suo                     </intent-filter>                               le applicazioni realizzate
                                                                                                                   siano tradotte in più lingue.
interno sono contenute delle sottoclassi statiche,               </activity>
                                                                                                                   Android aiuta gli
una per ciascuna tipologia di risorsa presente nel             </application>                                      sviluppatori consentendo
progetto: R.string, R.drawable, R.color e così via. In         <uses-sdk android:minSdkVersion="3" />              l’internazionalizzazione
ciascuno di questi gruppi vengono introdotti gli ID        </manifest>                                             delle risorse. Supponiamo
numerici che corrispondono alle risorse e ai valori                                                                di voler realizzare
                                                                                                                   un’applicazione sia in
conservati in res e nelle sue sotto-cartelle.              Il nome dell’applicazione, citato ben due volte
                                                                                                                   inglese sia in italiano.
Proviamo con un esempio pratico: facciamo il caso          all’interno del file, è stato richiamato mediante il    Prepariamo due differenti
che nel file res/values/strings.xml sia stata dichiara-    riferimento @string/app_name. Allo stesso modo,         file strings.xml con tutti i
ta la stringa app_name. Per richiamarla da codice          l’icona per l’applicazione, creata automatica-          messaggi di interfaccia,
Java, stando all’interno di una attività, si deve fare     mente da Eclipse al percorso res/drawable/icon.         uno in inglese e l’altro in
                                                                                                                   italiano. Adesso, invece
alla seguente maniera:                                     png, è stata riferita attraverso la dicitura @draw-
                                                                                                                   della cartella values,
                                                           able/icon. Adesso tocca alla classe TestReso            creiamo le due cartelle
Resources res = getResources();                            urcesActivity, il cui codice è riportato di seguito:    values-it (per l’italiano) e
String appName = res.getString(R.string.app_name);                                                                 values-en (per l’inglese) ed
                                                           package it.ioprogrammo.testresources;                   inseriamo al loro interno i
                                                                                                                   due file. È fatta! I dispositivi
                                                           import android.app.Activity;
                                                                                                                   Android che eseguiranno
                                                           import android.content.res.Resources;                   l’applicazione sceglieranno
CIAO MONDO RELOADED                                        import android.os.Bundle;                               automaticamente quale file
Mettiamo a frutto le nozioni acquisite quest’oggi,         import android.widget.TextView;                         caricare, in base alla loro
assemblando per la seconda volta un esempio                public class TestResourcesActivity extends Activity {   lingua predefinita.
del tipo “Ciao, Mondo!”. Questa volta, però, use-          @Override
remo la più corretta pratica delle risorse esterne         public void onCreate(Bundle savedInstanceState) {
per il nome dell’applicazione e per il messaggio                            super.onCreate(savedInstanceState);                L’AUTORE
presentato sullo schermo. Create il progetto                Resources res = getResources();
Android in Eclipse e chiamatelo TestResources.              String message = res.getString(R.string.message);
                                                                                                                   Carlo Pelliccia lavora
Il package di riferimento è it.ioprogrammo.testre-          TextView tv = new TextView(this);                      presso 4IT (www.4it.it),
sources, mentre l’attività principale deve essere           tv.setText(message);                                   dove si occupa di analisi e
TestResourcesActivity. Non appena il progetto è             setContentView(tv);                                    sviluppo software per
pronto, andiamo ad editare il file res/values/             }
                                                                                                                   piattaforme Java. Nella sua
                                                                                                                   carriera di technical writer
strings.xml:                                               }
                                                                                                                   ha pubblicato cinque
                                                                                                                   manuali ed oltre
<?xml version="1.0" encoding="utf-8"?>                     Il messaggio “Ciao, Mondo Androide!”, questa            centocinquanta articoli,
<resources>                                                volta, è stato caricato attraverso la classe            molti dei quali proprio tra le
   <string name="app_name">TestResources</string>          Resources ed il riferimento R.string.message.           pagine di ioProgrammo. Il
                                                                                                                   suo sito, che ospita anche
   <string name="message">Ciao, Mondo Androide!</string>
                                                                                                                   diversi progetti Java Open
</resources>                                                                                                       Source, è disponibile
                                                                                                                   all’indirizzo
Sono state dichiarate due stringhe: app_name               PROSSIMAMENTE                                           www.sauronsoftware.it
con valore “TestResources” e message con valore            Nel prossimo appuntamento approfondiremo i
“Ciao, Mondo Androide!”.                                   principi di programmazione delle attività, uno
Andiamo ora su AndroidManifest.xml:                        dei mattoni fondamentali delle applicazioni
                                                           Android.
<?xml version="1.0" encoding="utf-8"?>                                                     Carlo Pelliccia


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                            Novembre 2009 / 61G
                                                                                                                             15
                                                       Scopriamo cosa e come si programmano le “Attività”
                            Android programming Scopriamo cosa sono sono e come si programmano le “Attività”
                                 MOBILE �




COME IL SISTEMA
GESTISCE LE ATTIVITÀ
TERZO APPUNTAMENTO. LE “ATTIVITÀ” SONO IL COMPONENTE SOFTWARE PIÙ UTILIZZATO
DAI PROGRAMMATORI ANDROID. IN QUESTO ARTICOLO IMPAREREMO COS’È UN’ATTIVITÀ,
COME VIENE GESTITA DAL SISTEMA E COME POSSIAMO REALIZZARNE DI NOSTRE




                                         L
                                                 e applicazioni Android, come si è accennato             che le attività sono quei componenti di un’applica-
                                                 durante la prima lezione di questo corso, si            zione Android che fanno uso del display e che inte-
                                                 compongono di quattro mattoni fondamen-                 ragiscono con l’utente.
                                         tali: le attività (activity), i servizi (service), i broadca-   Dal punto di vista del programmatore, poi, possia-
                                         st receiver e i content provider. Ogni applicazione è           mo spingerci oltre e semplificare ulteriormente.
                                         formata da uno o più di questi mattoni. Non è detto             In maniera più pragmatica, un’attività è una classe
                                         che li contenga tutti: ad esempio potrebbe essere               che estende android.app.Activity. L’autore del codi-
                                         costituita da due attività e da un servizio, senza              ce, realizzando l’attività, si serve dei metodi eredi-
    ❑ CD ❑ WEB                           avere broadcast receiver né content provider. Nella             tati da Activity per controllare cosa appare nel
    corso_android_pt3.zip
                                         stragrande maggioranza dei casi, comunque, le                   display, per assorbire gli input dell’utente, per
                  cdrom.ioprogrammo.it
                                         applicazioni comprendono almeno un’attività. Le                 intercettare i cambi di stato e per interagire con il
                                         attività, di conseguenza, sono il più fondamentale              sistema sottostante.
                                         dei componenti di base delle applicazioni Android.



                                                                                                         CICLO DI VITA
                                         COS’È UN’ATTIVITÀ                                               DI UN’ATTIVITÀ
                                         Stando alla documentazione ufficiale, un’attività è             In un sistema desktop il monitor è sufficientemen-
                                         “una singola e precisa cosa che l’utente può fare”.             te spazioso da poter mostrare più finestre simulta-
                                         Proviamo a indagare le implicazioni di questa affer-            neamente. Perciò non è affatto raro lavorare con
                                         mazione. Partiamo dal fatto che l’utente, per fare              più programmi contemporaneamente attivi, le cui
                                         qualcosa, deve interagire con il dispositivo.                   finestre vengono affiancate o sovrapposte. Gli
                                         Domandiamoci come avvenga, nel caso di uno                      smartphone, invece, funzionano diversamente.
                                         smartphone, l’interazione tra l’uomo e la macchi-               Prima di tutto il display è piccolo, e pertanto ha
                                         na. Un ruolo essenziale, naturalmente, è svolto dai             poco senso affiancare due o più finestre di applica-
                                         meccanismi di input, come la tastiera e il touch-               zioni differenti. Poi non bisogna dimenticare che le
                                         screen, che permettono all’utente di specificare il             risorse di calcolo sono modeste, e perciò non è
                                         proprio volere. Le periferiche di input, tuttavia, da           buona cosa tenere simultaneamente in vita troppi
                                         sole non bastano. Affinché l’utente sappia cosa può             programmi. Per questi motivi le attività di Android
                                         fare e come debba farlo, ma anche affinché il                   hanno carattere di esclusività. È possibile mandare
                                         software possa mostrare all’utente il risultato ela-            in esecuzione più attività simultaneamente, ma
              REQUISITI
                                         borato, è necessario un canale aggiuntivo. Nella                soltanto un’attività alla volta può occupare il
                                         maggior parte dei casi questo canale è il display.              display. L’attività che occupa il display è in esecu-
Conoscenze richieste
   Java                                  Nella superficie dello schermo il software disegna              zione e interagisce direttamente con l’utente.
                                         tutti quegli oggetti con cui l’utente può interagire            Le altre, invece, sono ibernate e tenute nascoste in
Software                                 (bottoni, menu, campi di testo), e sempre sullo                 sottofondo, in modo da ridurre al minimo il consu-
    Java SDK (JDK) 5+,
    Eclipse 3.3+                         schermo viene presentato il risultato dell’elabora-             mo delle risorse di calcolo. L’utente, naturalmente,
                                         zione richiesta. Il ragionamento ci porta alla con-             può ripristinare un’attività ibernata e riprenderla
                                         clusione che, per fare qualcosa con il dispositivo, è           da dove l’aveva interrotta, riportandola in primo
                                         necessario usare lo schermo. Esiste perciò un                   piano. L’attività dalla quale si sta allontanando,
Impegno
                                         parallelo tra il concetto di attività, in Android, e            invece, sarà ibernata e mandata in sottofondo al
¥                                        quello di finestra, in un sistema desktop, benché               posto di quella ripristinata. Il cambio di attività può
Tempo di realizzazione
                                         non siano esattamente la stessa cosa. In generale,              anche avvenire a causa di un evento esterno. Il caso
                                         ad ogni modo, possiamo assumere con tranquillità                più ricorrente è quello della telefonata in arrivo: se

                                                                                                                                   h t t p : / / w w w. i o p r o g r a m m o . i t
     G 54 / Dicembre 2009
     16                                                                                                                                        And roi d pr o g r am m in g
     Scopriamo cosa sono e come si programmano le “Attività” Android programming
    Scopriamo cosa sono e come si programmano le “Attività”     � MOBILE


il telefono squilla mentre si sta usando la calcolatri-          permettono di killare le attività in sottofondo, ma
ce, quest’ultima sarà automaticamente ibernata e                 non sono previsti nel sistema di base.
mandata in sottofondo. L’utente, conclusa la chia-               I differenti passaggi di stato di un’attività attraver-
mata, potrà richiamare l’attività interrotta e ripor-            sano alcuni metodi della classe Activity che, come
tarla in vita, riprendendo i calcoli esattamente da              programmatori, possiamo ridefinire per intercetta-
dove li aveva interrotti.                                        re gli eventi di nostro interesse.
Visto che le attività ibernate, in termini di risorse di         La Fig.1 illustra la sequenza di chiamate ai metodi
calcolo, non consumano nulla, in Android il con-                 di Activity eseguite durante i passaggi di stato del-
cetto di chiusura delle attività è secondario e tenu-            l’attività. Entriamo nel dettaglio:
to nascosto all’utente. Ciò, di solito, spiazza chi è al
suo primo confronto con la programmazione dei                    • protected void onCreate(android.os.Bundle
dispositivi portatili. Le attività di Android non                  savedInstanceState)
dispongono di un bottone “x”, o di un tasto equiva-                Richiamato non appena l’attività viene creata.
lente, con il quale è possibile terminarle. L’utente,              L’argomento savedInstanceState serve per ripor-                    NOTA
di conseguenza, non può chiudere un’attività, ma                   tare un eventuale stato dell’attività salvato in pre-
può solo mandarla in sottofondo. Questo, comun-                    cedenza da un’altra istanza che è stata terminata.      ANDROID SDK 1.6
que, non significa che le attività non muoiano mai,                L’argomento è null nel caso in cui l’attività non       È stata da poco rilasciata la
anzi! Per prima cosa le attività possono morire                    abbia uno stato salvato.                                versione 1.6 del kit di
spontaneamente, perché hanno terminato i loro                    • protected void onRestart()                              sviluppo per Android. Molte
compiti. Insomma, anche se il sistema non ci forni-                Richiamato per segnalare che l’attività sta venen-      sono le novità incluse nella
                                                                                                                           nuova versione: oltre ai
sce automaticamente un bottone “chiudi”, possia-                   do riavviata dopo essere stata precedentemente          consueti bugfix e alle
mo sempre includerlo noi nelle nostre applicazio-                  arrestata.                                              migliorie generali, il
ni. In alternativa, la distruzione delle attività è com-         • protected void onStart()                                sistema comprende ora
pletamente demandata al sistema. I casi in cui                     Richiamato per segnalare che l’attività sta per         delle nuove API per il
un’attività può terminare sono due:                                diventare visibile sullo schermo.                       supporto delle gesture
                                                                                                                           e del text-to-speech.
                                                                 • protected void onResume()                               Se siete fermi alla versione
• L’attività è ibernata e il sistema, arbitrariamente,             Richiamato per segnalare che l’attività sta per         1.5, potete aggiornarvi
  decide che non è più utile e perciò la distrugge.                iniziare l’interazione con l’utente.                    partendo dall’indirizzo:
• Il sistema è a corto di memoria, e per recuperare              • protected void onPause()                                http://developer.android.c
  spazio inizia a “uccidere” bruscamente le attività               Richiamato per segnalare che l’attività non sta         om/sdk/
                                                                                                                           Oltre all’SDK, bisogna
  in sottofondo.                                                   più interagendo con l’utente.                           aggiornare anche l’ADT (il
Esistono poi dei task manager di terze parti che                 • protected void onStop()                                 plug-in per Eclipse).
                                                                   Richiamato per segnalare che l’attività non è più       Farlo è molto semplice:
                                                                   visibile sullo schermo.                                 aprite Eclipse e selezionate
                                                                 • protected void onDestroy()                              la voce di menu “Help »
                                                                                                                           Check for Updates”,
                                                                   Richiamato per segnalare che l’applicazione sta
                                                                                                                           controllate gli
                                                                   per essere terminata.                                   aggiornamenti disponibili e
                                                                                                                           selezionate quelli relativi ai
                                                                 La prassi richiede che, come prima riga di codice di      componenti Android. Dopo
                                                                 ciascuno di questi metodi, si richiami l’implemen-        aver scaricato e installato
                                                                                                                           gli aggiornamenti, aprite la
                                                                 tazione di base del metodo che si sta ridefinendo.
                                                                                                                           maschera della preferenze
                                                                 Ad esempio:                                               (voce di menu “Window »
                                                                                                                           Preferences”) e alla scheda
                                                                 protected void onStart() { super.onStart(); // ...}       “Android” provvedete ad
                                                                                                                           aggiornare il percorso
                                                                                                                           dell’SDK, in modo da
                                                                 È importante non dimenticare questa regola: le            puntare alla versione 1.6.
                                                                 attività sviluppate potrebbero non funzionare!            Con la voce di menu
                                                                                                                           “Window » Android SDK
                                                                                                                           and AVD Manager”, create
                                                                                                                           poi un AVD (Android Virtual
                                                                                                                           Device) compatibile con la
                                                                 DESCRIVERE UN’ATTIVITÀ                                    nuova versione del
                                                                 Dopo che si è creata un’attività, la si deve registrare   sistema.
                                                                 all’interno del descrittore dell’applicazione (il file
                                                                 AndroidManifest.xml), questo affinché il sistema
                                                                 sappia della sua esistenza. Per farlo si usa un tag
                                                                 <activity> all’interno del tag <application>:
Fig. 1: Ciclo di vita di un’attività. Sono illustrate le chia-
mate ai metodi che è possibile ridefinire per intercettare
i passaggi di stato                                              <?xml version="1.0" encoding="utf-8"?>


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                    Dicembre 2009 / 55 17
                                                                                                                                      G
                                                Scopriamo cosa e come si programmano le “Attività”
                     Android programming Scopriamo cosa sono sono e come si programmano le “Attività”
                          MOBILE �


                                   <manifest xmlns:android="http://schemas.                    Più semplicemente, gli intent sono dei messaggi
                                                                android.com/apk/res/android"   che il sistema manda a un’applicazione quando si
                                               package=" mypackage.mysubpackage " . . . >      aspetta che questa faccia qualcosa. Di come fun-
                                      <application . . . >                                     zionano gli intent e di cosa si compongono torne-
                                         <activity android:name=".MyActivity" . . . >. . .     remo certamente a parlare in futuro. Per ora ci
                                         </activity>                                           basta sapere che le attività, attraverso un intent-fil-
                                         ...                                                   ter, possono essere attivate in risposta ad uno spe-
                                      </application>                                           cifico evento. Gli intent-filter accettano figli di tre
                                   </manifest>                                                 tipi:

                                   Con l’attributo android:name si specifica il nome           • <action android:name="nome-azione">
                                   della classe registrata come attività. Si può espri-          Individua gli intent che richiedono l’azione spe-
                                   mere sia il suo percorso completo (ad esempio                 cificata.
                                   mypackage.mysubpackage.MyActivity) sia il nome              • <category android:name="nome-categoria">
                                   relativo rispetto al package dichiarato nel tag               Individua gli intent che appartengono alla cate-
                                   <manifest> sovrastante (ad esempio .MyActivity).              goria specificata.
                                   Altri attributi possono opzionalmente essere inse-          • <data android:mimeType="nome-tipo-mime">
                                   riti nel tag <activity>, allo scopo di meglio detta-          <data android:scheme="nome-schema-url">
                                   gliare l’attività che si sta registrando. Tra le tante        Individua gli intent che portano dati del tipo spe-
           NOTA                    cose che si possono fare, una delle più importanti è          cificato.
                                   quella di attribuire una label, cioè un’etichetta,
                                   all’attività. Si tratta, sostanzialmente, di un titolo      Le azioni, le categorie ed i tipi di dato che possono
      PROGRAMMA
    ANDROID IN C++                 che il sistema userà per riferirsi all’attività e per       essere usati sono, naturalmente, moltissimi.
      Una novità collegata al      presentarla all’utente. L’attributo da utilizzare è         Pian piano impareremo a conoscerli. Per ora ci
  rilascio della versione 1.6      android:label. Come si è spiegato nel numero pre-           interessa sapere che un’attività dotata di un intent-
         dell’Android SDK è la     cedente, in casi come questo è possibile sia scrive-        filter che include l’azione android.intent.
         possibilità di scrivere   re la stringa direttamente nell’XML sia fare riferi-        action.MAIN e la categoria android.intent.catego-
       applicazioni in C/C++,
      compilate poi in codice      mento ad una stringa memorizzata in un file                 ry.LAUNCHER viene identificata come l’attività
 nativo. Nella maggior parte       strings.xml sotto la directory res/values. Nel primo        principale dell’applicazione. Ciò significa che l’ap-
dei casi, comunque, rimane         caso, quindi, si userà una formula del tipo:                plicazione sarà elencata nel menù di sistema e che,
 conveniente programmare           <activity android:name=".MyActivity" android:               quando l’utente l’avvierà, sarà lanciata proprio l’at-
  Android in Java, poiché la       label="La mia attività">                                    tività marcata in tale maniera. Ecco perché, in tutti
           piattaforma è stata
         concepita per essere      Nel secondo caso, invece, si farà alla seguente             gli esempi dei mesi precedenti, abbiamo sempre
     programmata in questa         maniera:                                                    usato una formulazione del tipo:
 maniera. Esistono dei casi,       <activity android:name=".MyActivity" android:
tuttavia, in cui si deve agire     label="@string/my_activity_label">                          <activity android:name=".MyActivity" . . .>
                a basso livello,   Un altro attributo spesso usato con il tag <activity>         <intent-filter>
       scavalcando Java e la
      Dalvik Virtual Machine.      è android:icon, che permette di specificare un’ico-           <action android:name="android.intent.action.MAIN"/>
     Adesso è possibile farlo      na per l’attività. In questo caso si usa sempre il rife-      <category
  scaricando ed installando        rimento ad una immagine presente nella cartella               android:name="android.intent.category.LAUNCHER" />
        l’Android NDK (Native      res/drawable, qualcosa come:                                  </intent-filter>
         Development Kit), un      <activity android:name=".MyActivity" android:               </activity>
          addendum dell’SDK
    disponibile al medesimo        icon="@drawable/my_activity_icon">
    indirizzo di quest’ultimo.     Se non si specifica alcuna icona, l’attività eredita        Oltre all’attività principale, possiamo registrare in
                                   automaticamente l’icona definita nel sovrastante            AndroidManifest.xml quante attività vogliamo, da
                                   tag <application>. All’interno della coppia di tag          lanciare secondo necessità, come vedremo tra due
                                   <activity> … </activity>, invece, possono essere            paragrafi.
                                   allacciate delle relazioni particolari fra l’attività e
                                   l’applicazione e fra l’attività ed il sistema. In parti-
                                   colar modo, è possibile collegare all’attività un
                                   intent-filter:                                              IL PROGETTO
                                                                                               ACTIVITYDEMO
                                   <activity . . .>                                            Fermiamoci un attimo con la teoria e mettiamo
                                     <intent-filter> . . .</intent-filter>                     insieme in un esempio pratico i concetti appresi
                                   </activity>                                                 finora. Lo scopo è dimostrare il ciclo di vita delle
                                                                                               attività, attraverso una activity che registri in un log
                                   Nel dizionario di Android, un intent è “la descrizio-       tutti i suoi cambi di stato. Creiamo il progetto
                                   ne di un’operazione che deve essere eseguita”.              ActivityDemo, con package di riferimento it.iopro-


   G 56 / Dicembre 2009
                                                                                                                         h t t p : / / w w w. i o p r o g r a m m o . i t
   18                                                                                                                                And roi d pr o g r am m in g
       Scopriamo cosa sono e come si programmano le “Attività” Android programming
      Scopriamo cosa sono e come si programmano le “Attività”     � MOBILE


grammo.activitydemo, ed inseriamo al suo interno                android.com/apk/res/android" package="it.ioprogrammo.
la seguente omonima attività:                                                     activitydemo" android:versionCode="1"
                                                                                           android:versionName="1.0">
package it.ioprogrammo.activitydemo;                           <application android:icon="@drawable/icon"
import android.app.Activity; import android.os.Bundle;                              android:label="@string/app_name">
import android.util.Log;                                       <activity android:name=
public class ActivityDemo extends Activity                        ".ActivityDemo" android:label="@string/app_name">
{                                                              <intent-filter>
@Override                                                       <action android:name="android.intent.action.MAIN" />
  protected void onCreate(Bundle savedInstanceState)           <category
  {                                                              android:name="android.intent.category.LAUNCHER" />
          super.onCreate(savedInstanceState);                  </intent-filter>
          Log.i("ActivityDemo", "Richiamato                    </activity>
              onCreate() con bundle " + savedInstanceState);   </application>
  }                                                            <uses-sdk android:minSdkVersion="3" />
  @Override                                                    </manifest>
  protected void onRestart()
  {                                                            Non dimentichiamo di includere un file res/val-
          super.onRestart();                                   ues/strings.xml con le risorse riferite nel manifesto:               NOTA
          Log.i("ActivityDemo", "Richiamato onRestart()"); }
  @Override                                                    <?xml version="1.0" encoding="utf-8"?>
                                                                                                                          ALTRI ATTRIBUTI
    protected void onStart() {                                 <resources>
                                                                                                                          DEL TAG
          super.onStart();                                      <string name="app_name">ActivityDemo LABEL</string>       <ACTIVITY>
          Log.i("ActivityDemo", "Richiamato onStart()"); }     </resources>                                               Il tag <activity>, nel
    @Override                                                                                                             manifest dell’applicazione,
    protected void onResume() {                                L’applicazione è ora pronta per essere avviata.            ammette una grande
                                                                                                                          varietà di attributi, oltre a
          super.onResume();                                    Avviate l’emulatore e fate qualche prova.
                                                                                                                          quelli citati nell’articolo.
          Log.i("ActivityDemo", "Richiamato onResume()"); }    Mandate l’attività in secondo piano, magari azio-          Ad esempio con android:
    @Override                                                  nando qualche altra applicazione fra quelle                excludeFromRecents si può
    protected void onPause() {                                 disponibili nel sistema. Quindi date un’occhiata           fare in modo che l’attività
          super.onPause();                                     ai log emessi, per verificare il ciclo di vita dell’at-    non venga presentata
                                                                                                                          nell’elenco delle attività
          Log.i("ActivityDemo", "Richiamato onPause()"); }     tività. Usando Eclipse i log possono essere con-
                                                                                                                          lanciate di recente, con
    @Override                                                  sultati nella prospettiva di lavoro chiamata               android:screen Orientation
      protected void onStop() {                                “DDMS”, nella scheda “LogCat”.                             si può forzare un certo
          super.onStop();                                                                                                 orientamento dello
          Log.i("ActivityDemo", "Richiamato onStop()"); }                                                                 schermo e con
                                                                                                                          android:theme si può
      @Override
                                                                                                                          cambiare il tema grafico
      protected void onDestroy() {                             SOTTO-ATTIVITÀ                                             usato dall’attività. Un
          super.onDestroy();                                   Come spiegato in apertura, un’applicazione                 elenco completo è
          Log.i("ActivityDemo", "Richiamato onDestroy()");     Android può contenere più di un’attività. In que-          compreso nella
      }                                                        sto caso una soltanto sarà marcata come attività           documentazione ufficiale,
                                                                                                                          all’indirizzo:
}                                                              principale di lancio. Le altre saranno, invece,
                                                                                                                          http://developer.android.c
                                                               delle sotto-attività, che l’attività principale potrà      om/guide/topics/manifest/
Questo codice, oltre a mostrarci la prassi corretta            lanciare quando ce n’è bisogno. Realizzare una             activity-element.html
da applicare quando si ridefiniscono i metodi che              sotto-attività è semplice tanto quanto realizzare
intercettano i cambi di stato dell’attività, ci fa fare        l’attività principale: ancora una volta è sufficien-
conoscenza con la classe android.util.Log. Come è              te estendere android.app.Activity.
facile intuire, la classe contiene dei metodi statici          Le attività secondarie vanno poi registrate nel file
per scrivere nel log di sistema. Il metodo i(), usato          AndroidManifest.xml, senza però applicare l’in-
nell’esempio, salva delle righe di log di livello INFO.        tent-filter con l’azione e la categoria usate invece
Altri metodi disponibili sono v() per il livello VER-          dall’attività principale. L’attività principale può
BOSE, d() per il livello DEBUG, w() per il livello             lanciare delle sotto-attività ricorrendo al metodo
WARN, ed e() per il livello ERROR. Registriamo l’at-           startActivity(). Questo accetta come argomento
tività nel manifesto dell’applicazione, marcandola             un oggetto di tipo android.content.Intenet che,
come attività principale di lancio:                            come è facile intuire, rappresenta un intent. Con
                                                               questo intento bisogna esprimere quale sotto-
<?xml version="1.0" encoding="utf-8"?>                         attività deve essere avviata. Immaginiamo di
<manifest xmlns:android="http://schemas.                       voler lanciare la sotto-attività rappresentata dalla


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                  Dicembre 2009 / 57G
                                                                                                                                   19
                                               Scopriamo cosa e come si programmano le “Attività”
                    Android programming Scopriamo cosa sono sono e come si programmano le “Attività”
                         MOBILE �


                                 classe MySubActivity. Tutto quello che dovremo             package it.ioprogrammo.subactivitydemo;
                                 fare, dall’interno dell’attività principale, è formu-      import android.app.Activity; import android.os.Bundle;
                                 lare un’istruzione del tipo:                               import android.view.View;import android.widget.Button;
                                 startActivity(new Intent(this, MySubActivity.class));      public class SubActivity extends Activity
                                 La sotto-attività verrà lanciata e prenderà lo             {
                                 schermo al posto di quella principale.                      @Override
                                                                                             protected void onCreate(Bundle savedInstanceState){
                                                                                                super.onCreate(savedInstanceState);
                                                                                                Button button = new Button(this);
                                                                                                button.setText("Termina SubActivity");
                                                                                                button.setOnClickListener(new View.OnClickListener()
                                                                                                {
                                                                                                    @Override
                                                                                                    public void onClick(View v) {finish();}});
                                                                                                    setContentView(button); }
                                                                                            }


                                                                                            Dal codice apprendiamo una nozione nuova:
                                                                                            un’attività, sia principale sia secondaria, può termi-
                                                                                            nare e chiudersi spontaneamente invocando il pro-
Fig. 2: Il log di ActivityDemo permette di osservare il ciclo di vita dell’attività         prio metodo finish(). Registriamo adesso le due
                                                                                            attività nel descrittore dell’applicazione:

                                                                                            <?xml version="1.0" encoding="utf-8"?>
                                 SUBACTIVITYDEMO                                            <manifest xmlns:android="http://schemas.
                                 Mettiamo in pratica quanto descritto nel paragrafo                                        android.com/apk/res/android"
                                 precedente. Il progetto si chiama SubActivityDemo,          package="it.ioprogrammo.subactivitydemo"
                                 e il package di riferimento è it.ioprogrammo.subac-                                             android:versionCode="1"
                                 tivitydemo. All’interno di questo inseriremo due            android:versionName="1.0">
                                 attività: MainActivity e SubActivity. La prima sarà         <application android:icon="@drawable/icon"
                                 poi registrata come attività principale e conterrà un                              android:label="@string/app_name">
                                 tasto per avviare la seconda. SubActivity conterrà,         <activity android:name=".MainActivity"
                                 invece, un tasto per chiuderla e passare all’attività          android:label="@string/main_activity_label">
                                 principale:                                                    <intent-filter>

          L’AUTORE                                                                              <action android:name="android.intent.action.MAIN" />
                                 package it.ioprogrammo.subactivitydemo;                        <category
                                 import android.app.Activity;                                android:name="android.intent.category.LAUNCHER" />
       Carlo Pelliccia lavora
   presso 4IT (www.4it.it),      import android.content.Intent;                             </intent-filter>
 dove si occupa di analisi e     import android.os.Bundle; import android.view.View;        </activity>
      sviluppo software per      import android.widget.Button;                              <activity android:name=".SubActivity"
piattaforme Java. Nella sua      public class MainActivity extends Activity {                android:label="@string/sub_activity_label"></activity>
 carriera di technical writer
                                 @Override                                                  </application>
       ha pubblicato cinque
            manuali ed oltre     public void onCreate(Bundle savedInstanceState) {          <uses-sdk android:minSdkVersion="3" />
    centocinquanta articoli,       super.onCreate(savedInstanceState);                      </manifest>
molti dei quali proprio tra le     Button button = new Button(this);
  pagine di ioProgrammo. Il        button.setText("Lancia SubActivity");                    Per completare ecco il file res/values/strings.xml:
 suo sito, che ospita anche
                                   button.setOnClickListener(new View.OnClickListener() {
 diversi progetti Java Open
       Source, è disponibile       @Override                                                <?xml version="1.0" encoding="utf-8"?>
                 all’indirizzo     public void onClick(View v) { startSubActivity(); }});   <resources>
   www.sauronsoftware.it              setContentView(button); }                             <string name="app_name">ManyActivitiesDemo</string>
                                 private void startSubActivity() {                          <string name="main_activity_label">Main Activity</string>
                                   Intent intent = new Intent(this, SubActivity.class);     <string name="sub_activity_label">Sub Activity</string>
                                   startActivity(intent);                                   </resources>
                                 }}
                                                                                            Non resta che eseguire l’esempio e provare il lancio
                                 Quanto spiegato nel paragrafo precedente è stato           e la chiusura della sotto-attività.
                                 messo in pratica all’interno del metodo startSub
                                 Activity(). Studiamo il codice di SubActivity:                                                                  Carlo Pelliccia



   G 58 / Dicembre 2009
                                                                                                                           h t t p : / / w w w. i o p r o g r a m m o . i t
   20                                                                                                                                  And roi d pr o g r am m in g
                                     Programmazione delle
       Programmazione delle interfacce utente con Android interfacce utente con Android
                   MOBILE �                                      Android programming




INTERFACCE: LAYOUT
E COMPONENTI
QUARTO APPUNTAMENTO. INIZIA LA TRATTAZIONE DEI CONCETTI E DEGLI STRUMENTI DI
ANDROID PER LA COSTRUZIONE E LA GESTIONE DELLE INTERFACCE UTENTE. SI COMINCIA
CON I WIDGET ED I LAYOUT DI BASE, INDISPENSABILI IN OGNI APPLICAZIONE




                                         D
                                                  opo aver scoperto cosa sono e come fun-         (come la documentazione). Se volete, potete
                                                  zionano le attività, studiamo ora come si       anche selezionare tutto, in modo da disporre di
                                                  costruiscono e si gestiscono le interfacce      più versioni del sistema per sviluppare e testare
                                         utente in Android. Apprenderemo le pratiche              le vostre applicazioni. Azionando il tasto “Install
                                         utili per costruire oggetti grafici in grado di inte-    Selected” vi verrà chiesto di accettare le licenze
                                         ragire con chi impugna il device. Si tratta di un        dei componenti selezionati. Usate l’opzione
                                         passaggio cruciale del nostro percorso di                “Accept All” e proseguite poi con il tasto “Install
                                         apprendimento: tutti i dispositivi mobili di             Accepted”. Il tool procederà al download e all’in-
    ❑ CD ❑ WEB                           nuova generazione puntano tantissimo sull’inte-          stallazione      dei    componenti        richiesti.
    corso_android_pt3.zip
                                         razione con l’utente.                                    Naturalmente potrete ripetere questa operazio-
                  cdrom.ioprogrammo.it
                                                                                                  ne in futuro, per controllare il rilascio di nuove
                                                                                                  versioni del sistema e per configurarle nel vostro
                                                                                                  SDK. Dopo aver concluso il download e l’installa-
                                         ANDROID 2.0                                              zione, non dimenticatevi di creare uno o più
                                         ED IL NUOVO SDK                                          device virtuali (AVD) per i vostri sviluppi (voce
                                         Collegatevi all’indirizzo di riferimento per il kit di   “Virtual Devices” nel tool) compatibili con
                                         sviluppo di Android, cioè:                               Android 2.0 e con le altre versioni che avete sca-
                                         http://developer.android.com/sdk/                        ricato. Se sviluppate con Eclipse, come suggerito
                                         Da qui scaricare il più recente SDK disponibile          in questo corso, dovrete anche aggiornare l’ADT
                                         per la vostra piattaforma (al momento in cui             e collegarlo alla nuova installazione dell’SDK.
                                         questo articolo viene scritto, la versione più
                                         recente è la r3). Estraete l’archivio scaricato sul
                                         vostro disco rigido, al percorso che preferite. Con
                                         la riga di comando, adesso, posizionatevi sulla          VIEW E VIEWGROUP
                                         directory tools del kit di sviluppo. Lanciate il         Andiamo all’argomento del giorno, cioè alle
                                         comando:                                                 interfacce grafiche e ai componenti che le attività
                                                                                                  possono usare per interagire con l’utente. I primi
                                         android                                                  due concetti che dobbiamo assorbire si chiama-
                                                                                                  no View e ViewGroup, e corrispondono alla
                                         Verrà caricata una GUI che vi permette di gestire        maniera di Android di classificare ed organizzare
                                         i device virtuali ed i componenti aggiuntivi. Il         ciò che è sullo schermo. I bottoni, i campi di
              REQUISITI
                                         nuovo SDK, appena scaricato e installato, è prati-       testo, le icone e tutti gli altri congegni di un’inter-
                                         camente vuoto. Contiene solo gli strumenti di            faccia grafica sono oggetti View. I ViewGroup,
 Conoscenze richieste
    Java                                 sviluppo, e al suo interno non c’è traccia di alcu-      invece, sono dei contenitori che possono mette-
                                         na versione del sistema. La prima cosa da fare,          re insieme più oggetti View. I ViewGroup, inoltre,
 Software                                quindi, è selezionare la voce “Available Packages”,      sono a loro volta degli oggetti View, e di conse-
     Java SDK (JDK) 5+,
     Eclipse 3.3+                        che permette di visionare ed installare i compo-         guenza un possono contenere altri ViewGroup.
                                         nenti aggiuntivi, tra i quali ci sono anche le diffe-    Grazie a questa intuizione è possibile organizza-
                                         renti versioni della piattaforma. Una volta sele-        re i componenti sullo schermo secondo uno
                                         zionata la voce, espandete l’elenco dei compo-           schema ad albero, come quello di Fig.2.
 Impegno
                                         nenti disponibili per l’unica fonte inizialmente         I componenti View estendono tutti la classe base
¥                                        registrata. Selezionate le piattaforme con le quali      android.view.View. Nella libreria standard di
Tempo di realizzazione
                                         intendete sviluppare (sicuramente la nuova 2.0)          Android ci sono già molti componenti di questo
                                         ed i componenti aggiuntivi che giudicate utili           tipo, soprattutto nel pacchetto android.widget.

                                                                                                                            h t t p : / / w w w. i o p r o g r a m m o . i t
     G 50 / Gennaio 2010
A n d ro id p r o g r a m m ing                                                                                                                                 21
                      Programmazione delle interfacce utente con Android interfacce utente con Android
                        Android programming         Programmazione delle     � MOBILE


Oltre ai widget di base, ad ogni modo, è sempre
possibile estendere la classe View e realizzare i
propri componenti custom. Il più delle volte non
c’è bisogno di farlo, poiché quelli forniti da
Android bastano per tutte le principali necessità.
È comunque importante che sia data questa pos-
sibilità. La classe android.view.ViewGroup è una
speciale estensione di View. Come accennato in
precedenza, e come rappresentato in figura, un
ViewGroup è una speciale View che può contene-
                                                        Fig. 2: Android organizza i componenti sullo schermo
                                                        attraverso i componenti di base View e ViewGroup


                                                                                                                           NOTA
                                                        ViewGroup è una classe astratta. Pertanto non
                                                        può essere istanziata direttamente. Come nel             PROBLEMI SSL
                                                        caso di View, è possibile realizzare il proprio          Se, nel tentativo di
                                                        ViewGroup custom, ma il più delle volte conviene         scaricare gli aggiornamenti
                                                        scegliere fra le tante implementazioni messe a           automatici dell’SDK, vi
                                                        disposizione dalla libreria Android. Queste              doveste imbattere in un
                                                                                                                 errore SSL, potete
                                                        implementazioni differiscono nella maniera di            risolverlo alla seguente
                                                        presentare i componenti che sono al loro inter-          maniera: nell’elenco di
                                                        no: alcuni li mettono uno dopo l’altro, altri li         sinistra scegliete la voce
Fig. 1: Dopo il download della nuova versione della     organizzano in una griglia, altri ancora possono         “Settings”, attivate la
piattaforma si deve configurare un device virtuale      essere usati per avere una gestione a schede dello       checkbox “Force https://...
che la installi, altrimenti non sarà possibile usarla                                                            sources to be fetched
per lo sviluppo                                         schermo, e così via. Ovviamente conosceremo              using http://…”,
                                                        presto tutte le principali implementazioni di            confermate con il tasto
                                                        ViewGroup.                                               “Save & Apply”. Adesso
re altre View. Per questo motivo gli oggetti            Una volta che, combinando oggetti View e                 tornate sulla scheda
ViewGroup dispongono di diverse implementa-             ViewGroup, si è ottenuta l’interfaccia utente che        “Available Packages” e
                                                                                                                 tentate di nuovo il
zioni del metodo addView(), che permette pro-           si desidera, è necessario che questa venga               download degli
prio di aggiungere una nuova View al gruppo:            mostrata sullo schermo. Come abbiamo scoper-             aggiornamenti.
                                                        to mediante alcuni esempi preliminari, le attività
• public void addView(View child)                       (cioè gli oggetti android.app.Activity) mettono a
  Aggiunge un oggetto View al gruppo.                   disposizione un metodo setContentView(), dispo-
                                                        nibile nelle seguenti forme:
• public void addView(View child, int index)
  Aggiunge un oggetto View al gruppo, specifi-          • public void setContentView(View view)
  candone la posizione attraverso un indice               Mostra sullo schermo l’oggetto View specifica-
  (index).                                                to.
                                                        • public void setContentView( View view,
• public void addView(View child, int width,              ViewGroup.LayoutParams params)
  int height) Aggiunge un oggetto View al grup-           Mostra sullo schermo l’oggetto View specifica-
  po, specificandone larghezza (width) ed altezza         to, applicando una serie di parametri di visua-
  (height).                                               lizzazione ed organizzazione del componente
                                                          (params).
• public void addView( View child, View
  Group.LayoutParams params)
  Aggiunge un oggetto View al gruppo, applican-
  do una serie di parametri di visualizzazione ed       WIDGET
  organizzazione del componente (params).               Con il termine widget (congegno) si indicano quei
                                                        componenti di base per l’interazione con l’uten-
• public void addView(View child, int index,            te, come i bottoni, le check box, le liste, i campi di
  ViewGroup.LayoutParams params)                        testo e così via. I widget predefiniti di Android
  Aggiunge un oggetto View al gruppo, specificando      estendono tutti (direttamente o indirettamente)
  la posizione attraverso un indice (index) ed appli-   la classe View, e sono conservati nel package
  cando una serie di parametri di visualizzazione ed    android.widget. Esaminiamone alcuni in una
  organizzazione del componente (params).               veloce panoramica:

h t t p : / / w w w. i o p r o g r a m m o . i t
    22                                                                                                           2010/ o g r G
                                                                                                         Gennaio And roi d pr 51am m in g
                                    Programmazione delle
      Programmazione delle interfacce utente con Android interfacce utente con Android
                  MOBILE �                                      Android programming


                                  ANDROID.WIDGET.TEXTVIEW                                    ANDROID.WIDGET.DATEPICKER
                                  Permette di mostrare del testo all’utente. Il              Un componente che permette di scegliere una data
                                  messaggio da visualizzare può essere imposta-              selezionando giorno, mese ed anno. La data impo-
                                  to con il metodo setText(), che può accettare              stata dall’utente può essere recuperata servendosi
                                  come parametro sia una stringa sia un riferi-              dei metodi getDayOfMonth(), getMonth() e getYear().
                                  mento a risorsa preso dal gruppo R.string (cfr.
                                  ioProgrammo 144).                                          ANDROID.WIDGET.TIMEPICKER
                                                                                             Un componente che permette di scegliere un orario
                                  ANDROID.WIDGET.EDITTEXT                                    selezionando ora e minuto. L’orario impostato dal-
                                  Estende TextView e permette all’utente di modifica-        l’utente può essere recuperato servendosi dei meto-
                                  re il testo mostrato. Il testo digitato può essere recu-   di getCurrentHour() e getCurrent Minute().
                                  perato con il metodo getText(), che restituisce un
Fig. 3: TextView
                                  oggetto del tipo android.text.Editable. Gli oggetti        ANDROID.WIDGET.ANALOGCLOCK
                                  Editable sono simili alle stringhe, ed infatti imple-      Un componente che mostra all’utente un orolo-
                                  mentano l’interfaccia java.lang.Char Sequence.             gio analogico.

                                  ANDROID.WIDGET.BUTTON                                      ANDROID.WIDGET.DIGITALCLOCK
                                  Realizza un bottone che l’utente può premere o             Un componente che mostra all’utente un orolo-
Fig. 4: EditText
                                  cliccare. Il componente espande TextView, e per            gio digitale.
                                  questo è possibile impostare il testo mostrato al
                                  suo interno con il metodo setText(), sia con para-         Tutti gli oggetti discussi finora richiedono, nei
                                  metro stringa sia con riferimento a risorsa del            loro costruttori, un oggetto che estenda la classe
                                  gruppo R.string.                                           astratta android.content.Context. Si tratta di una
                                                                                             struttura che permette l’accesso al sistema e che
Fig. 5: Button                    ANDROID.WIDGET.IMAGEVIEW                                   costituisce il contesto di esecuzione dell’applica-
                                  Un componente che permette di mostrare un’im-              zione. Non dovete preoccuparvi di come ottene-
                                  magine. Metodi utili sono: setImage Bitmap(), che          re oggetti di questo tipo: android.app.Activity
                                  accetta un oggetto di tipo android.graphics.Bitmap;        estende indirettamente Context, per cui dall’in-
                                  setImageDrawable(), che accetta un argomento               terno di un’attività, vi sarà sufficiente usare la
                                  android. graphics. drawable. Drawable; setImage            parola chiave this. Ad esempio:
                                  Resource(), che accetta un riferimento a risorsa
                                  drawable.                                                  Button b = new Button(this);

                                  ANDROID.WIDGET.IMAGEBUTTON                                 La considerazione vale per le attività, ma anche
                                  Un bottone con un’immagine. Estende Image                  per tanti altri contesti della programmazione
                                  View, e quindi espone gli stessi metodi di que-            Android: più o meno tutte le classi che sono mat-
                                  st’ultima per impostare l’immagine mostrata.               toni fondamentali del sistema estendono diretta-
Fig. 6: ImageView                                                                            mente o indirettamente la classe astratta
                                  ANDROID.WIDGET.CHECKBOX                                    android.content.Context.
                                  Questo componente realizza una casella di spunta           Sul CD-Rom allegato alla rivista trovate, insieme
                                  (check box, appunto). Estende Button e TextView,           con i codici di questo articolo, gli esempi d’uso di
                                  pertanto il testo a fianco della casella può essere        ciascuno dei widget citati.
                                  impostato con i metodi setText() già noti..
Fig. 7: ImageButton
                                  ANDROID.WIDGET.RADIOBUTTON
                                  Questo componente realizza un bottone radio.               LAYOUT
                                  Come nel caso di CheckBox, le classi base Button e         Con il termine layout (disposizione, impagi-
                                  TextView forniscono i metodi necessari per l’impo-         nazione), in Android, si identificano tutti quei
Fig. 8: CheckBox                  stazione del testo visualizzato. Un bottone radio, da      ViewGroup utilizzabili per posizionare i widget
                                  solo, non ha senso. Due o più bottoni radio, per-          sullo schermo. Android fornisce una serie di
                                  tanto, possono essere raggruppati all’interno di un        layout predefiniti. Esaminiamone alcuni.
                                  android.widget.RadioGroup. L’utente, così, potrà
                                  attivare soltanto una delle opzioni del gruppo.            android.widget.FrameLayout
                                                                                             Il più semplice e basilare dei layout: accetta un
                                  ANDROID.WIDGET.TOGGLEBUTTON                                widget, lo allinea in alto a sinistra e lo estende
Fig. 9: RadioButton               Un bottone “ad interruttore”, che può essere cioè          per tutta la dimensione disponibile al layout
                                  “on” o “off”. Può essere usato per far attivare o          stesso. Ecco un semplice esempio di utilizzo, che
                                  disattivare delle opzioni.                                 allarga un bottone all’intera area a disposizione


   G 52 / Gennaio 2010
                                                                                                                     h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                          23
                      Programmazione delle interfacce utente con Android interfacce utente con Android
                        Android programming         Programmazione delle     � MOBILE


di un’attività:                                                    CAL. Con l’orientamento orizzontale i compo-
                                                                   nenti verranno messi tutta sulla stessa riga, uno
Button button = new Button(this);                                  dopo l’altro. Con l’allineamento verticale, inve-
button.setText("Bottone");                                         ce, si procede lungo una colonna, e quindi i
FrameLayout layout = new FrameLayout(this);                        widget saranno uno sopra l’altro.
layout.addView(button);                                            Esaminiamo il caso dell’allineamento orizzon-
setContentView(layout);                                            tale. In questo caso i componenti vengono
                                                                   introdotti lungo una sola linea. Il sistema accet-
android.widget.RelativeLayout                                      ta di aggiungere componenti finché c’è spazio.
Come FrameLayout, vuole un solo componente al                      Se si va di poco oltre la dimensione della riga, il
suo interno, ma a differenza di quest’ultimo, lo                   sistema tenta un aggiustamento restringendo i           Fig. 10: ToggleButton
disegna nelle sue dimensioni ideali, senza allar-                  componenti al di sotto delle loro dimensioni
garlo per ricoprire l’intera area a disposizione.                  ideali. Raggiunto un certo limite, comunque, il
Per default, il componente viene allineato in alto                 sistema si rifiuta di andare oltre, ed i compo-
a sinistra, ma è possibile controllare l’allinea-                  nenti di troppo non saranno più visualizzati. Il
mento servendosi del metodo setGravity().                          metodo setGravity(), nell’allineamento orizzon-
Questo accetta un argomento di tipo int, che è                     tale, può essere usato per decidere dove posizio-
bene scegliere fra le costanti messe a disposizio-                 nare e come organizzare la riga dei componenti          Fig. 11: DatePicker
ne nella classe android.view.Gravity. I valori possi-              rispetto allo spazio disponibile.
bili, nel caso di RelativeLayout, sono i seguenti:                 Ecco un esempio:

• Gravity.TOP allinea il widget in alto.                           Button button1 = new Button(this);
• Gravity.BOTTOM allinea il widget in basso.                       button1.setText("Bottone 1");
• Gravity.LEFT allinea il widget a sinistra.                       Button button2 = new Button(this);
• Gravity.RIGHT allinea il widget a destra.                        button2.setText("Bottone 2");                           Fig. 12: TimePicker
• Gravity.CENTER_HORIZONTAL allinea il wid-                        Button button3 = new Button(this);
  get al centro orizzontalmente.                                   button3.setText("Bottone 3");
• Gravity.CENTER_VERTICAL allinea il widget al                     LinearLayout layout = new LinearLayout(this);
  centro verticalmente.                                            layout.setOrientation(LinearLayout.HORIZONTAL);
• Gravity.CENTER allinea il widget al centro sia                   layout.setGravity(Gravity.CENTER_HORIZONTAL);
  orizzontalmente sia verticalmente.                               layout.addView(button1);
                                                                   layout.addView(button2);
Più costanti Gravity, purché non in contrasto fra                  layout.addView(button3);
di loro, possono essere concatenate in un solo                     setContentView(layout);                                 Fig. 13: AnalogClock
valore servendosi dell’operatore binario OR (che
in Java si rende con il simbolo |, detto pipe). Ad                 Nei LinearLayout verticali i componenti ven-
esempio per allineare in basso a destra si scrive:                 gono aggiunti uno sopra all’altro, ed espansi
                                                                   in orizzontale fino ad occupare tutto lo spazio
Gravity.BOTTOM | Gravity.RIGHT                                     a disposizione del layout. In questo caso
                                                                   setGravity() può essere usato per decidere se
Ecco un campione di codice che dimostra l’uso                      allineare la colonna in alto, in basso o al cen-        Fig. 14: DigitalClock
di un RelativeLayout all’interno di un’attività:                   tro. Il sistema aggiunge componenti finché c’è
                                                                   spazio nella colonna. Superato il limite, i
Button button = new Button(this);                                  componenti di troppo non vengono visualiz-
button.setText("Bottone");                                         zati. Ecco un esempio:
RelativeLayout layout = new RelativeLayout(this);
layout.setGravity(Gravity.TOP |                                    Button button1 = new Button(this);
                                     Gravity.CENTER_HORIZONTAL);   button1.setText("Bottone 1");
layout.addView(button);                                            Button button2 = new Button(this);
setContentView(layout);                                            button2.setText("Bottone 2");
                                                                   Button button3 = new Button(this);
ANDROID.WIDGET.LINEARLAYOUT                                        button3.setText("Bottone 3");
Un layout utile per disporre più componenti                        ...
uno di seguito all’altro, sia orizzontalmente sia
verticalmente. Una volta creato il layout, il suo                  La classe android.widget.RadioGroup, presen-            Fig. 15: Un bottone,
                                                                                                                           inserito in un
orientamento può essere stabilito chiamando il                     tata sopra e utile per mettere insieme più
                                                                                                                           FrameLayout, viene
metodo setOrientation(), con argomento pari a                      RadioButton, estende LinearLayout e gode per-           espanso fino alla dimen-
LinearLayout.HORIZONTAL o LinearLayout.VERTI-                      tanto di tutte le proprietà appena mostrate.            sione massima del layout


h t t p : / / w w w. i o p r o g r a m m o . i t
    24                                                                                                                       2010/ g r am m
                                                                                                                     GennaioAnd roi d pr o 53Gin g
                                    Programmazione delle
      Programmazione delle interfacce utente con Android interfacce utente con Android
                  MOBILE �                                      Android programming


                                  ANDROID.WIDGET.TABLELAYOUT                                Si faccia attenzione al fatto che gli indici delle
                                  Un layout che permette di sistemare i compo-              colonne, in Android, partono da 0. TableLayout
                                  nenti secondo uno schema a tabella, suddiviso             dispone inoltre di alcuni metodi di comodo che
                                  cioè in righe e colonne. I TableLayout vanno              permettono, in un sol colpo, di applicare le mede-
                                  costruiti aggiungendo al loro interno degli ogget-        sime impostazioni di shrink o di stretch a tutte le
                                  ti TableRow, ciascuno dei quali forma una riga            colonne. Questi metodi sono setShrinkAll Colum-
                                  della tabella.                                            ns() e setStretchAllColumns().
                                  Ogni riga è suddivisa in colonne. In ciascuna             Sul CD-Rom allegato alla rivista trovate, insieme
                                  cella può essere inserito un componente. La gra-          con i codici di questo articolo, gli esempi d’uso di
                                  vità, cioè il metodo setGravity(), può essere usato       ciascuno dei layout citati.
                                  sia su TableLayout che su TableRow, per stabilire
                                  gli allineamenti relativi. Ecco un semplice esem-
Fig. 16: RelativeLayout           pio di tre righe e tre colonne:
utilizzato per disporre un                                                                  METTERE INSIEME
bottone, nelle sue dimen-         int rows = 3;                                             WIDGET E LAYOUT
sioni ideali
                                  int columns = 3;                                          I widget ed i layout illustrati sinora, naturalmen-
                                  TableLayout layout = new TableLayout(this);               te, devono essere combinati in maniera coerente.
                                  layout.setGravity(Gravity.CENTER);                        I layout, in maniera particolare, possono e devo-
                                  for (int i = 0; i < rows; i++) {                          no essere annidati l’uno dentro l’altro, finché non
                                      TableRow tableRow = new TableRow(this);               si ottiene il design desiderato. Proviamo insieme
Fig. 17: Un LinearLayout              tableRow.setGravity(Gravity.CENTER);                  con un esempio semplice ed efficace. Facciamo il
che allinea tre bottoni in            for (int j = 0; j < columns; j++)                     caso che dobbiamo realizzare, in un’attività, una
orizzontale, al centro                {                                                     maschera di input attraverso la quale l’utente
                                            Button button = new Button(this);               può specificare il proprio nome, il proprio cogno-
                                            button.setText("Bottone " +                     me ed il proprio sesso. Al termine dell’operazio-
                                                                ((columns * i) + j + 1));   ne, l’utente può salvare i dati con un tasto “Salva”
                                            tableRow.addView(button);                       o annullarli con il bottone “Annulla”. Ecco il codi-
                                      }                                                     ce necessario per realizzare quanto teorizzato:
                                      layout.addView(tableRow);
                                  }                                                         TextView label1 = new TextView(this);
Fig. 18: Un TableLayout           setContentView(layout);                                   label1.setText("Nome:");
con nove bottoni disposti                                                                   EditText edit1 = new EditText(this);
su tre righe e tre colon-
                                  Si faccia attenzione al fatto che, se la tabella          TextView label2 = new TextView(this);
ne
                                  eccede le dimensioni a disposizione, una parte            label2.setText("Cognome:");
                                  di essa non sarà visibile. Su come Android                EditText edit2 = new EditText(this);
                                  ripartisca la dimensione da assegnare a cia-              ...
                                  scuna colonna, si può agire con i seguenti
                                  metodi:                                                   Si sono adoperati dei widget TextView, per le eti-
                                                                                            chette, EditText, per i campi ad immissione libe-
                                  • public void setColumnCollapsed(int column               ra, RadioButton (con RadioGroup), per la selezio-
                                    Index, boolean isCollapsed)                             ne tra un elenco di opzioni, e Button, per i botto-
                                    Stabilisce se una colonna è collapsed. Quando           ni di azione finali. I componenti sono stati dispo-
                                    una colonna è collapsed, non viene mostrata             sti sullo schermo annidando diversi tipi di layout.
Fig. 19: Una maschera di            sullo schermo.                                          I campi del modulo sono stati messi insieme ser-
immissione dati realizza-                                                                   vendosi di un TableLayout, che dispone le eti-
ta combinando più wid-
get e più layout                  • public void setColumnShrinkable(int column              chette sulla colonna di sinistra ed i widget mani-
                                    Index, boolean isShrinkable)                            polabili su quella di destra. La pulsantiera con i
                                    Stabilisce se una colonna è shrinkable. Quando          bottoni “Salva” e “Annulla” è stata invece realiz-
                                    una colonna è shrinkable, il sistema cerca di           zata servendosi di un LinearLayout orizzontale,
                                    restringerla il più possibile, per fare in modo che     che affianca e centra i due widget. I due layout,
                                    occupi poco spazio.                                     infine, sono stati messi insieme servendosi di un
                                                                                            terzo contenitore, nello specifico un Linear
                                  • public void setColumnStretchable(int column             Layout verticale, che ha disposto la tabella in alto
                                    Index, boolean isStretchable)                           e la pulsantiera sotto di questa. Tutto, infine, è
                                    Stabilisce se una colonna è stretchable. Quando         stato centrato sullo schermo. Il risultato ottenuto
                                    una colonna è stretchable, il sistema tende ad          è mostrato in figura.
                                    allargarla fornendogli lo spazio extra di cui
                                    dispone.                                                                                                 Carlo Pelliccia



   G 54 / Gennaio 2010
                                                                                                                       h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                            25
                                                       delle interfacce utente con Android (seconda parte)
                            Android programming Design Design delle interfacce utente con Android (parte 2)
                                 MOBILE �




INTERFACCE IN XML
PER ANDROID
QUINTO APPUNTAMENTO. VI È SEMBRATO CHE IL DESIGN JAVA DI UN’INTERFACCIA UTENTE,
IN ANDROID, SIA LUNGO E NOIOSO? NESSUN PROBLEMA! OGGI IMPAREREMO A SERVIRCI
DELL’XML PER VELOCIZZARE E SEMPLIFICARE L’OPERAZIONE




                                         L
                                                o scorso mese abbiamo imparato a disporre            menti; ora, invece, si assiste ad un’inversione di ten-
                                                sullo schermo i principali widget messi a            denza. La programmazione Web, ad esempio, ha
                                                disposizione da Android: bottoni, caselle di         dimostrato quanto sia più facile gestire un’interfac-
                                         testo, check box e via discorrendo. La logica che per-      cia utente descrivendone i componenti con un lin-
                                         mea la loro creazione ed il loro utilizzo, come abbia-      guaggio a marcatori, anziché con un linguaggio di
                                         mo potuto osservare, non si discosta di molto da            programmazione.
                                         quella adottata da altre librerie Java per le interfacce    I linguaggi a marcatori come HTML ed XML ben si
                                         utente, come AWT e Swing. Questo modo di creare le          prestano a questo genere di operazioni: sono più
    ❑ CD ❑ WEB                           GUI è potente, ma anche estremamente tedioso.               facili da leggere e da scrivere, sia per l’uomo sia per
    corso_android_pt5.zip
                                         Ogni volta che si deve utilizzare un widget, lo si deve     la macchina (cioè per gli editor visuali). Così oggi le
                  cdrom.ioprogrammo.it
                                         creare, personalizzare ed inserire in un contenitore        piattaforme moderne applicano alla programma-
                                         predisposto in precedenza. Sin dalle origini delle          zione di applicazioni native il medesimo principio,
                                         interfacce basate sui widget, i creatori delle piat-        fornendo agli sviluppatori framework ed editor
                                         taforme di sviluppo hanno cercato di porre rimedio          basati perlopiù su XML. Uno dei primi tentativi in tal
                                         a questo difetto. Nella maggior parte dei casi si è         senso ad aver avuto successo è stato XUL, nato in
                                         fatto ricorso ad editor visuali: il programmatore,          casa Mozilla ed impiegato per le GUI di Firefox e di
                                         anziché scrivere codice, trascina i componenti sul-         altre applicazioni della fondazione, poi importato
                                         l’editor, dimensionandoli ad occhio ed impostando-          anche in altri ambiti ed ambienti. Mi ricollego ora al
                                         ne le caratteristiche salienti mediante delle proce-        discorso precedente, ripetendo per l’ennesima volta
                                         dure guidate. Il lavoro sporco lo fa l’editor in sot-       che Android è un sistema operativo di moderna
                                         tofondo, generando ed interpretando il codice di            concezione. Come abbiamo imparato il mese scor-
                                         programmazione necessario. Questo approccio è               so, le GUI possono essere realizzate con un approc-
                                         valido, ma da solo non costituisce una vera e propria       cio classico, basato sul codice di programmazione.
                                         soluzione al problema. Il codice prolisso e difficile       Spesso e volentieri, però, è più semplice ricorrere
                                         da gestire, infatti, è ancora lì: l’ambiente di sviluppo    all’approccio moderno, basato su XML, che Android
                                         non ha fatto altro che nascondere la sporcizia sotto        rende disponibile nativamente.
                                         il tappeto. Gli editor visuali, poi, sono molto difficili
                                         da realizzare, perché devono interpretare e generare
                                         del codice complesso, ed infatti ne esistono davvero
                                         pochi di buona qualità. Il codice generato automati-        LAYOUT XML
                                         camente, infine, è spesso un obbrobrio. L’ambiente,         Veniamo al dunque. Avrete sicuramente notato che
              REQUISITI
                                         infatti, non ha l’intelligenza sufficiente per scrivere e   la struttura predefinita di un progetto Android crea-
                                         mantenere un codice leggibile e performante.                to in Eclipse contiene sempre la directory res/layout.
Conoscenze richieste
   Java                                  Con l’avvento dei browser moderni, di AJAX e degli          Abbiamo già conosciuto alcune fra le sottodirectory
                                         interpreti di nuova concezione, si sono portate sul         di res e, in tutti i casi, abbiamo osservato come la
Software                                 Web molte applicazioni che, fino a ieri, erano              piattaforma di sviluppo gestisse in maniera speciale
    Java SDK (JDK) 5+,
    Eclipse 3.3+                         appannaggio esclusivo degli ambienti desktop e dei          le differenti categorie di risorse possibili. La cartella
                                         linguaggi compilati. I client di posta elettronica, ad      layout non fa eccezione. Al suo interno possono
                                         esempio, stanno scomparendo a favore delle web-             essere disposti dei file XML che il sistema interpre-
                                         mail. Il proliferare delle applicazioni Web sta facen-      terà come descrizioni dichiarative dei layout e dei
Impegno
                                         do maturare velocemente gli strumenti di sviluppo           widget che saranno poi usati in una o più attività
¥                                        propri di questo ambito. All’inizio la programmazio-        dell’applicazione. Un esempio, in questo caso, vale
Tempo di realizzazione
                                         ne Web sottraeva idee alla programmazione delle             più di mille parole. Il mese scorso abbiamo chiuso
                                         applicazioni native, emulandone approcci e stru-            con questo codice:

                                                                                                                                h t t p : / / w w w. i o p r o g r a m m o . i t
     G 50 / Febbraio 2010
     26                                                                                                                                     And roi d pr o g r am m in g
                                                 (seconda
      Design delle interfacce utente con Android (parte 2) parte) Android programming
       Design delle interfacce                                       � MOBILE


TextView label1 = new TextView(this);                             riporta il nome del file aperto. L’ambiente, anche in
label1.setText("Nome:");                                          questo caso, fornisce alcune utili agevolazioni, come
EditText edit1 = new EditText(this);                              l’auto-completamento dei tag, degli attributi e dei
TextView label2 = new TextView(this);                             valori, con tanto di aiuto in linea, come mostrato in
label2.setText("Cognome:");                                       figura.
...


Si tratta del codice necessario per assemblare un
modulo per l’inserimento dei dati anagrafici di una               RICHIAMARE
persona (nome, cognome, sesso). Era un buon espe-                 UN LAYOUT XML
diente per mostrare l’utilizzo combinato di alcuni                Nella directory res/layout si possono memorizzare
layout (LinearLayout, TableLayout) ed alcuni widget               quanti file si desidera. L’ambiente li compila e gene-
(TextView, EditText, Button, RadioButton).                        ra automaticamente un riferimento verso ciascuno
L’esempio ha l’effetto collaterale di dimostrare come             di essi nella classe R, all’interno gruppo layout. Ad               NOTA
sia poco naturale usare Java per assemblare un’in-                esempio il file res/layout/mioLayout.xml avrà il suo
terfaccia utente: il codice è poco leggibile, i nomi              riferimento in R.layout.mioLayout. Questo riferi-        ANDROID 2.0.1
delle variabili poco significativi, e bisogna concen-             mento, passando al codice Java, può essere utilizza-     (API 6)
trarsi molto per capire chi contiene cosa. È il classi-           to per invocare e adoperare il layout realizzato. La     Anche questo mese c’è un
co caso in cui il formato XML è più vantaggioso:                  classe Activity, ad esempio, dispone di una versione     aggiornamento di Android
                                                                  di setContentView() che accetta come argomento un        da segnalare (sono
                                                                                                                           velocissimi e spesso
<?xml version="1.0" encoding="utf-8"?>                            riferimento ad un oggetto di tipo layout.
                                                                                                                           quando la rivista è già in
<LinearLayout                                                     Continuando con l’esempio XML del paragrafo pre-         edicola già è disponibile
xmlns:android="http://schemas.android.com/apk/res                 cedente       (che    va     salvato    al   percorso    l’aggiornamento
                                                      /android"   res/layout/main.xml), realizziamo un’attività in         successivo!). Ai primi di
                android:layout_width="fill_parent"                grado di caricare e mostrare il layout realizzato:       Dicembre è stata
                                                                                                                           pubblicata la versione
                android:layout_height="fill_parent"
                                                                                                                           2.0.1 del sistema, che
                ...                                               package it.ioprogrammo.xmllayoutdemo1;                   corrisponde alle API livello
                                                                  import android.app.Activity;                             6 (la versione precedente
Questo XML, dopo averci fatto l’occhio, risulta                   import android.os.Bundle;                                era la 2.0 - API 5). In
molto più semplice da gestire del suo corrispettivo                                                                        questo caso si tratta di un
                                                                                                                           rilascio di manutenzione,
Java. Anzitutto, per quanto riguarda la composizio-
                                                                                                                           che corregge qualche bug
ne dei layout, l’utilizzo dell’indentatura permette di                                                                     ed introduce solo piccoli
individuare immediatamente chi è il contenitore e                                                                          cambi nelle API, perlopiù
chi il contenuto. Gli attributi di XML, poi, sono                                                                          relativi allo strato Bluetooth
molto più semplici ed intuitivi, rispetto ai metodi del                                                                    e alla nuova gestione dei
                                                                                                                           contatti introdotta con la
tipo setProprietà() di Java. Con gli attributi è più
                                                                                                                           versione 2.0. Si segnala poi
semplice impostare le proprietà di ogni singolo                                                                            che anche l’SDK è stato
componente, come il testo visualizzato, il padding,                                                                        aggiornato alla versione r4.
la gravità e così via. Creare un editor visuale in grado                                                                   È possibile aggiornare i
di leggere e scrivere questo XML, inoltre, è estrema-                                                                      propri componenti
                                                                                                                           servendosi della procedura
mente più facile che realizzare un editor in grado di
                                                                                                                           automatizzata descritta nel
fare lo stesso con del codice Java. In Eclipse, insieme                                                                    numero scorso, oppure
con il plug-in ADT per lo sviluppo dei progetti                                                                            scaricando il nuovo
Android, ne avete già installato uno. Provate a crea-                                                                      software a partire
re un file di layout in un progetto Android, sotto il                                                                      dall’indirizzo:
                                                                                                                           http://developer.android.
percorso res/layout. Facendo doppio clic sul file,
                                                                                                                           com/sdk/
l’ambiente lo aprirà nel suo editor visuale. Qui è pos-
sibile aggiungere layout e widget semplicemente
pescandoli dal menu sulla sinistra e trascinandoli
sulla schermata al centro, che rappresenta l’interfac-
cia grafica così come apparirà nello smartphone.
Selezionando un componente è possibile accedere
all’elenco delle sue proprietà, mostrate nella scheda
“Properties” in basso. Da qui è possibile manipolare
i parametri del componente. Con un po’ di pratica si
riesce a costruire velocemente qualsiasi tipo di
interfaccia. È comunque possibile lavorare “a mano”               Fig. 1: Un form che permette all’utente l’inserimento
                                                                  dei suoi dati anagrafici di base
sul codice XML, attivando la linguetta in basso che

h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                    Febbraio 2010/ 51 27
                                                                                                                                     G
                                                delle interfacce utente con Android (seconda parte)
                     Android programming Design Design delle interfacce utente con Android (parte 2)
                          MOBILE �


                                  public class XMLLayoutDemo1Activity extends Activity     @string/titoloApplicazione
                                  {
                                                                                           Bene, la stessa identica cosa può essere fatta in
                                             @Override                                     un XML di layout. Ad esempio, si può ricorrere a
                                             public void onCreate(Bundle                   questa funzionalità quando si imposta il testo
                                                                     savedInstanceState)   mostrato in un bottone. Invece di scrivere:
                                  {
                                  super.onCreate(savedInstanceState);                      <Button android:text="Salva" />
                                                       setContentView(R.layout.main);
                                             }                                             Si può scrivere:

                                  }                                                        <Button
                                                                                                 android:text="@string/etichettaBottoneSalva" />
                                  Sul CD-Rom allegato alla rivista trovate il proget-
                                  to Android completo avviabile con l’emulatore.           A patto, ovviamente, di aver creato in res/values
                                                                                           un file XML che definisca la risorsa stringa
           NOTA
                                                                                           etichettaBottoneSalva, come ad esempio:

                        XML       REGOLE GENERALI                                          <?xml version="1.0" encoding="utf-8"?>
 Se non siete pratici di XML
   e di linguaggi a marcatori     Entriamo un po’ più nel dettaglio del formato XML        <resources>
      correte il rischio di non   usato per descrivere un layout. Come è facile intuire,             <string
condividere quanto ribadito       i tag adoperabili al suo interno corrispondono ai               name="etichettaBottoneSalva">Salva</string>
       in questo articolo, e di   nomi dei widget e dei layout manager descritti nel-      </resources>
 considerare più semplice il
                                  l’articolo del mese scorso. In pratica al widget Java
      design delle interfacce
         utente a mezzo di un     android.widget.TextView corrisponde il tag XML           La regola vale non soltanto per le stringhe, ma
                  linguaggio di   <TextView>, al layout manager android.widget.            per tutte le categorie di risorse. Ricapitoliamole:
      programmazione come         LinearLayout corrisponde <LinearLayout>, e così
Java. Se la pensate così, vi      via. Potete riprendere il numero del mese scorso e       •   @array, per gli array.
   garantisco, è solo perché
                                  desumere da voi le corrispondenze fra classi e tag. È    •   @color, per i colori.
  ancora non siete riusciti a
cogliere l’essenza di XML e       invece importante sapere che il namespace da uti-        •   @dimen, per le dimensioni.
  del suo utilizzo. Vi anticipo   lizzare è: http://schemas.android.com/apk/res/android    •   @drawable, per i valori drawable, ma anche
          che non dovete farvi    Normalmente lo si fa dichiarando il namespace nel            per le immagini messe in res/drawable.
spaventare: XML è nato per        primo tag utilizzato (quello di ordine superiore),       •   @layout, per richiamare altri layout.
 essere semplice, e dunque
                                  abbinandogli lo shortname android. In breve, il          •   @raw, per i file nella cartella res/raw.
 è anche facile. Ecco alcuni
   link per studiare cosa sia     modello da seguire è il seguente:                        •   @string, per le stringhe.
        XML e come funzioni:                                                               •   @style, per gli stili.
                                  <tag1 xmlns:android="http://
http://it.wikipedia.org/wik                       schemas.android.com/apk/res/android"
                      i/XML
                                             android:attr1="val1"
 http://xml.html.it/guide/le
 ggi/58/guida-xml-di-base/                   android:attr2="val2">
http://www.mrwebmaster.               <tag2 android:attr1="val1" android:attr2="val2" />
 it/xml/guide/guida-xml_9/            <tag2 android:attr1="val1" android:attr2="val2" />
http://www.risorse.net/xm         </tag1>
                l/guida.asp

                                  Là dove gli attributi sono utilizzati per immettere
                                  Un valore libero, ad esempio un testo, una
                                  dimensione, un colore, un’immagine e così via, è
                                  possibile sfruttare i riferimenti ad altri materiali
                                  conservati nella gerarchia della cartella res.
                                  Quando è stato trattato lo speciale file
                                  AndroidManifest.xml (cfr. ioProgrammo 144)
                                  abbiamo imparato ad usare i riferimenti del tipo:

                                  @tipo/nome


                                  Ad esempio, per richiamare la stringa
                                  “titoloApplicazione” definita in un XML sotto            Fig. 2: L’editor visuale compreso con ADT per la crea-
                                  res/values, è possibile fare:                            zione guidata dei layout XML in ambiente Eclipse



   G 52 / Febbraio 2010
                                                                                                                     h t t p : / / w w w. i o p r o g r a m m o . i t
   28                                                                                                                            And roi d pr o g r am m in g
                                                (seconda
     Design delle interfacce utente con Android (parte 2) parte) Android programming
      Design delle interfacce                                       � MOBILE


ASSEGNARE                                                                    avente l’ID specificato come argomento. Il botto-
UN ID AI COMPONENTI                                                          ne può a questo punto essere recuperato e mani-
A ciascun componente dichiarato nell’XML, sia                                polato (ad esempio per aggiungere un gestore di
esso un contenitore o un widget, è possibile asse-                           evento, come impareremo prossimamente):
gnare un identificativo, utile per rintracciare suc-
cessivamente il componente. Per assegnare un                                 Button button = (Button)
identificativo si deve utilizzare l’attributo id:                                                   findViewById(R.idBottoni.salva);


<Tag android:id="..." />


Per assegnare l’ID è necessario seguire una parti-                           ATTRIBUTI COMUNI
colare sintassi, basata sul seguente modello:                                Gli attributi applicabili ad un tag variano a seconda
                                                                             del componente cui fanno riferimento. In alcuni                        NOTA
@+nomeGruppo/nomeId                                                          casi gli attributi sono obbligatori, mentre in altri
                                                                             sono opzionali. Per esplorare tutti gli attributi di ogni   NAMESPACE
                                                                                                                                         I namespace di XML, per
Questa sintassi fa sì che nella classe R venga                               specifico widget, di conseguenza, è meglio affidarsi
                                                                                                                                         semplificare, sono
introdotto, se non esiste già, il gruppo nomeGrup-                           alle procedure guidate di un editor visuale, come           l’equivalente dei package
po, e che al suo interno venga memorizzato il                                quello di Eclipse ADT descritto sopra. Gli stessi attri-    in Java. Chi “inventa” un
riferimento all’ID nomeId. Sarà pertanto possibi-                            buti, naturalmente, sono esaustivamente riportati           nuovo gruppo di tag, per
le ricorrere all’ID, nel codice Java, usando il rife-                        anche nella documentazione ufficiale. Tutto ciò per         regola, deve inserirli in un
                                                                                                                                         namespace, in modo che
rimento:                                                                     dire che, in generale, non ci inalbereremo subito
                                                                                                                                         possano essere utilizzati
                                                                             nello studio di tutti gli attributi possibili.              senza andare in collisione
R.nomeGruppo.nomeId                                                          Ci concentreremo invece su quelli comuni o                  con eventuali altri tag
                                                                             comunque più interessanti. I primi due che esami-           omonimi di un altro autore.
Facciamo il caso di questo bottone:                                          niamo sono sempre obbligatori, e si chiamano lay-           I package di Java hanno la
                                                                                                                                         forma aaa.bbb.ccc, mentre
                                                                             out_width e layout_height. Servono per decretare
                                                                                                                                         i namespace di XML sono
<Button android:id="@+idBottoni/salva"                                       come si relazioni l’oggetto rispetto alle dimensioni        un URL del tipo
                                                   android:text="Salva" />   del suo contenitore. Due sono i valori possibili:           http://aaa/bbb/ccc. Benché
                                                                                                                                         questo sia un indirizzo Web
                                                                             • wrap_content                                              a tutti gli effetti, non è detto
                                                                                                                                         che debba per forza
                                                                               Rende il componente grande tanto quanto
                                                                                                                                         esserci un file da scaricare
                                                                               impongono i suoi sotto-componenti. In pratica             a quel percorso, anche se
                                                                               tutti i sotto-componenti vengono dimensionati             in genere l’autore ci mette
                                                                               rispetto, possibilmente, alla loro dimensione idea-       la definizione dei tag e
                                                                               le, e poi il contenitore che li contiene viene dimen-     degli attributi previsti dal
                                                                                                                                         namespace. A ciascuno dei
                                                                               sionato di conseguenza.
                                                                                                                                         namespace importati in un
                                                                             • fill_parent                                               tag XML è possibile
                                                                               Allarga il componente fino a fargli occupare tutto        associare uno shortname,
                                                                               lo spazio a sua disposizione concessogli dal suo          cioè un nome breve, utile
                                                                               contenitore d’ordine superiore.                           per richiamare tag ed
                                                                                                                                         attributi del namespace
                                                                                                                                         senza ambiguità. Per
                                                                             Ad esempio:                                                 approfondire i namespace
                                                                                                                                         e per qualche esempio
                                                                             <Button android:layout_width="wrap_content"                 pratico:
Fig. 3: Anche passando all’editing manuale dei layout                                        android:layout_height="wrap_content"
XML è possibile usufruire di alcune agevolazioni in                                                                                      http://xml.html.it/articoli/l
                                                                                                            android:text="Salva" />
ambiente Eclipse ADT, come l’auto-completamento                                                                                          eggi/1648/il-misterioso-
e l’help in linea per tag ed attributi                                                                                                   mondo-dei-namespaces/
                                                                             Questo bottone sarà grande tanto quanto basta a
                                                                             mostrare la scritta “Salva”. Quest’altro invece:

In Java sarà possibile richiamarlo adoperando il                             <Button android:layout_width="fill_parent"
riferimento:                                                                                     android:layout_height="fill_parent"
                                                                                                            android:text="Salva" />
R.idBottoni.salva
                                                                             Sarà allargato, sia in orizzontale sia in verticale,
Ad esempio le attività dispongono del metodo                                 fino ad occupare tutto lo spazio messo a sua
findViewById() che, come il nome lascia presup-                              disposizione. Altri attributi condivisi da tutti i
porre, ricerca nel layout caricato un componente                             componenti sono quelli definiti nella classe View,


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                  Febbraio 2010/ 53G
                                                                                                                                                  29
                                              delle interfacce utente con Android (seconda parte)
                    Android programming DesignDesign delle interfacce utente con Android (parte 2)
                         MOBILE �


                                 ereditati poi da tutti i widget e tutti i layout. Fra          Permettono di stabilire una dimensione massima
                                 questi si segnalano:                                           del componente, attraverso una misura scritta let-
                                                                                                teralmente o riferita da res/values.
                                 • minWidth e minHeight
                                   Permettono di specificare una dimensione mini-             • gravity
                                   ma per il componente. La misura deve essere                  Stabilisce la gravità applicata al componente. I
                                   espressa letteralmente, specificando l’unità di              valori possibili sono: top, bottom, left, right, cen-
                                   misura, oppure riferendo una dimensione defini-              ter_vertical, center_horizontal, center, fill_horizon-
                                   ta sotto res/values. (cfr. ioProgrammo 144).                 tal, fill_vertical, fill, clip_vertical e clip_horizontal.

                                 • paddingLeft, paddingTop, paddingRight,                     I tanti componenti che derivano da TextView (tra cui
                                   paddingBottom e padding                                    i diversi tipi di bottoni) hanno a loro disposizione:
                                   Permettono di specificare il padding (margine
                                   interno) del componente (cfr. ioProgrammo 146).            • text
                                   I primi quattro attributi permettono di distingue-           Permette di impostare il testo visualizzato, attra-
                                   re la misura di padding assegnata in ogni direzio-           verso un valore letterale o un riferimento a stringa
          L’AUTORE                 ne, mentre il quinto permette di assegnare a tutte           memorizzata sotto res/values.
                                   e quattro le direzioni il medesimo padding con
       Carlo Pelliccia lavora      un’istruzione sola. I valori espressi devono essere        Una particolare estensione di TextView è EditText.
   presso 4IT (www.4it.it),                                                                   Con EditText si realizza una casella di input, che per-
                                   dotati di unità di misura, o in alternativa fare rife-
 dove si occupa di analisi e
      sviluppo software per        rimento ad una dimensione nota in res/values.              mette all’utente di immettere del testo. In questo
piattaforme Java. Nella sua                                                                   caso possono tornare utili i seguenti attributi:
 carriera di technical writer    • visibility
       ha pubblicato cinque        Accetta tre possibili valori: 0 (visibile), 1 (invisibi-   • hint
            manuali ed oltre                                                                    Un suggerimento da visualizzare quando non c’è
                                   le), 2 (scomparso). Nel primo caso, che è quello di
    centocinquanta articoli,
molti dei quali proprio tra le     default, il componente è visibile. Nel secondo               del testo visualizzato.
  pagine di ioProgrammo. Il        caso il componente non è visibile, ma lo spazio
 suo sito, che ospita anche        spettante viene riservato e mantenuto vuoto. Nel           • password
 diversi progetti Java Open        terzo caso il componente è invisibile e nessuno              Un booleano (true o false) che indica se il campo
       Source, è disponibile                                                                    contiene una password. In questo caso il testo
                                   spazio gli viene assegnato durante il disegno del
                 all’indirizzo
   www.sauronsoftware.it           layout, proprio come non fosse mai esistito. La              viene camuffato in modo da non risultare leggibi-
                                   visibilità di un componente può essere poi mani-             le ad un occhio indiscreto.
                                   polata a runtime da codice, con il metodo
                                   setVisibility().                                           • numeric
                                                                                                Rende il campo di tipo numerico. Si deve specifi-
                                 Esistono poi dei tag non comuni a tutti i widget, ma           care uno o più valori (separandoli con pipe) fra
                                 molto diffusi. Tra questi:                                     integer, signed e decimal. Il primo indica un valo-
                                                                                                re intero, il secondo un valore numerico con
                                 • width e height                                               segno, il terzo di un valore decimale.
                                   Permettono di stabilire una dimensione precisa
                                   del componente, attraverso una misura scritta let-         • digits
                                   teralmente o riferita da res/values.                         Da usare se il campo è numerico. Permette di spe-
                                                                                                cificare quali cifre è possibile utilizzare. Ad esem-
                                 • maxWidth e maxHeight                                         pio il valore “123” farà sì che l’utente possa inseri-
                                                                                                re nel campo sono le cifre “1”, “2” e “3”.

                                                                                              Vi invitiamo a consultare la documentazione ufficia-
                                                                                              le, per completare da voi la panoramica facendo
                                                                                              qualche esperimento anche con gli attributi meno
                                                                                              ricorrenti.




                                                                                              PROSSIMAMENTE
                                                                                              Il prossimo mese proseguiremo la nostra trattazione
Fig. 4: Dimensionare un componente rispetto al suo contenitore. Da sinistra a
                                                                                              delle interfacce utente, parlando di eventi.
destra: wrap_content su layout_width e layout_height; wrap_content su
layout_width e fill_parent su layout_height; fill_parent su layout_width e wrap_con-
tent su layout_height; fill_parent su layout_width e su layout_height.                                                                          Carlo Pelliccia



   G 54 / Febbraio 2010
                                                                                                                          h t t p : / / w w w. i o p r o g r a m m o . i t
   30                                                                                                                                 And roi d pr o g r am m in g
                                                       Android: digitazione
                                                Android: tocco e tocco e digitazione Android programming
                                         MOBILE �




GESTIRE IL TOUCH
SU ANDROID
SESTO APPUNTAMENTO. IN QUESTA PUNTATA DEL CORSO IMPAREREMO LE VARIE TECNICHE
PER INTERCETTARE LE AZIONI DI TOCCO E DIGITAZIONE ESEGUITE DALL’UTENTE SUI WIDGET
PRESENTI NEL DISPLAY, IN MODO DA REAGIRE DI CONSEGUENZA




                                           N
                                                   ei due precedenti appuntamenti abbiamo               super(context);
                                                   conosciuto i principali widget di Android e      }
                                                   le tecniche utili per richiamarli e disporli
                                           nel display dello smartphone. Oggi impareremo a              @Override
                                           raccogliere l’input dell’utente, e lo faremo intercet-           public boolean onTouchEvent(MotionEvent event) {
                                           tando gli eventi scatenati dai widget.                             super.onTouchEvent(event);
                                                                                                              int action = event.getAction();
                                                                                                              if (action == MotionEvent.ACTION_DOWN) {
    ❑ CD ❑ WEB                                                                                                    Toast toast = Toast.makeText(getContext(),
    corso_android_pt6.zip
                                           I METODI DI CALLBACK                                                                                    "Bottone cliccato!",
                  cdrom.ioprogrammo.it
                                           Tutti i widget di Android dispongono di una serie di                                            Toast.LENGTH_SHORT);
                                           metodi di callback, con nomi del tipo onTipo                           toast.show();
                                           Evento(). Questi metodi vengono richiamati auto-                       return true;
                                           maticamente ogni volta che il corrispondente                       }
                                           evento è riscontrato sul widget. Mi spiego meglio                return false;
                                           con un esempio concreto. La classe android.wid-              }
                                           get.Button, che abbiamo conosciuto nel corso delle       }
                                           due puntate precedenti, definisce uno speciale
                                           metodo chiamato onTouchEvent(). Questo metodo            Il metodo onTouchEvent() riceve in ingresso un
                                           è eseguito automaticamente ogni volta che il botto-      argomento di tipo android.view.MotionEvent, che
                                           ne viene toccato dall’utente, attraverso il touch        riporta tutte le informazioni relative all’evento di
                                           screen del suo dispositivo. Sono molti i metodi di       tocco riscontrato sul bottone. La versione superio-
                                           questa categoria, ed ogni widget ha i propri.            re del metodo (cioè quella definita in Button) viene
                                           Ciascun metodo ha le sue regole e la sua firma:          richiamata con la riga:
                                           parametri e valore di ritorno, insomma, cambiano
                                           di caso in caso. La documentazione ufficiale delle       super.onTouchEvent(event);
                                           API di Android, come sempre, presenta l’elenco
                                           esaustivo (in inglese) per ciascun widget. Lo svilup-    Questo, nel caso specifico, è necessario affinché l’e-
                                           patore interessato alla gestione di uno specifico        vento venga gestito graficamente: la definizione
                                           evento deve individuare il metodo di suo interesse,      base del metodo contenuta in Button fa sì che il
                                           quindi estendere il widget e ridefinire il metodo        bottone, quando sottoposto a pressione, cambi il
              REQUISITI
                                           individuato. Proviamo a farlo proprio con il meto-       suo aspetto ed il suo colore, per mostrare reattività
                                           do onTouchEvent() di Button, rendendo il bottone         al tocco dell’utente (con il tema predefinito di
 Conoscenze richieste
    Java                                   reattivo al singolo “clic da dito”:                      Android 2.0, il bottone cambia da grigio ad aran-
                                                                                                    cione).
 Software                                  package it.ioprogrammo.buttonclickdemo1;                 Dopo aver eseguito la versione base del metodo, la
     Java SDK (JDK) 5+,
     Eclipse 3.3+                                                                                   nostra versione ridefinita controlla i dettagli dell’e-
                                           import android.content.Context;                          vento. Se si tratta del primo tocco riscontrato sul
                                           import android.view.MotionEvent;                         bottone (ACTION_DOWN), viene mostrato all’u-
                                           import android.widget.Button;                            tente un messaggio di notifica (“Bottone clicca-
 Impegno
                                           import android.widget.Toast;                             to!”). Altri filtri possono essere applicati per inter-
¥                                                                                                   cettare ulteriori varianti dell’evento di tocco, ad
 Tempo di realizzazione
                                           public class MyButton extends Button {                   esempio ACTION_MOVE per un trascinamento e
                                             public MyButton(Context context) {                     ACTION_UP per l’azione di rilascio del pulsante

                                                                                                                                   h t t p : / / w w w. i o p r o g r a m m o . i t
     G 54 / Marzo 2010
A n d ro id p r o g r a m m ing                                                                                                                                       31
                             Android programming Android: tocco e digitazione
                                                        Android: tocco e digitazione MOBILE
                                                                                   �


(dito sollevato dal display).                                         setContentView(layout);
Il metodo onTouchEvent(), infine, richiede la resti-              }
tuzione di un valore booleano, che serve per indi-            }
care se l’evento è stato effettivamente gestito oppu-
re no. L’implementazione restituisce true nel caso
di un evento ACTION_DOWN, effettivamente gesti-
to attraverso il messaggio mostrato all’utente,               EVENT LISTENER
mentre restituisce false in tutti gli altri casi.             La ridefinizione dei metodi di callback è una tecni-
                                                              ca che funziona, ma non è molto pratica: ogni volta
                                                              che si usa un widget bisogna estenderlo e generare
                                                              quindi un’altra classe, in modo da poter ridefinire il
                                                              metodo (o i metodi) di callback di proprio interes-
                                                              se. Questo, di per sé, è scomodo e prolisso. Quanti
                                                              widget possono esserci in un’applicazione di media                   NOTA
                                                              complessità? Fra bottoni, checkbox, etichette,
                                                              campi di testo e via discorrendo, il numero è sicu-        TOAST
                                                              ramente elevato. Ecco allora che la velocità di svi-       “Toast” è la parola usata
                                                              luppo viene frenata dal dover definire e catalogare        nel gergo dei dispositivi
                                                              tante classi quanti sono i widget che si vogliono uti-     mobili per identificare le
                                                              lizzare. Un vero incubo! La ridefinizione dei meto-        finestrelle pop-up con un
                                                                                                                         avviso rivolto all’utente.
                                                              di di callback, pertanto, è una pratica che serve solo     Si chiamano così perché
                                                              in determinati casi, principalmente durante la             nelle loro implementazioni
                                                              creazione di componenti custom. Ad esempio è               più classiche spuntano
                                                              possibile estendere View per creare un componen-           fuori dalla parte bassa del
                                                              te personalizzato. È lecito, lo si può fare, e probabil-   display e somigliano ad un
                                                                                                                         toast che salta fuori dal
                                                              mente prima o poi vi servirà di farlo. Per un inter-       tostapane a cottura
                                                              vento di questo genere, dunque, non c’è nulla di           ultimata. In Android, come
                                                              male nel ridefinire ed utilizzare i metodi di call-        si evince dagli esempi
                                                              back, anzi l’operazione sarebbe sicuramente                mostrati nell’articolo, gli
                                                              necessaria. Per tutti gli altri usi quotidiani dei wid-    avvisi toast possono essere
                                                                                                                         realizzati servendosi della
                                                              get pronti all’uso, invece, Android mette a disposi-       classe
                                                              zione un meccanismo più semplice e sbrigativo,             android.widget.Toast.
                                                              basato sull’utilizzo dei cosiddetti event listener.        Ad ogni modo, ne
                                                              Scopriamo insieme di cosa si tratta. Tutti i widget        parleremo nuovamente
Fig. 1: In questo esempio l’evento di primo tocco sul         mettono a disposizione una seconda serie di meto-          in seguito.
bottone viene gestito mostrando un avviso all’utente
                                                              di, questa volta del tipo setOnTipo EventoListener().
                                                              Il widget Button, ad esempio, dispone del metodo
                                                              setOnClickListener(). Attraverso i metodi di questa
La classe MyButton può essere ora impiegata all’in-           categoria è possibile registrare al widget degli event
terno di un’attività, come abbiamo imparato a fare            listener, cioè delle istanze di speciali classi, realiz-
due numeri fa:                                                zate appositamente per ricevere notifica ogni volta
                                                              che lo specifico evento accade. Per ciascun diffe-
package it.ioprogrammo.buttonclickdemo1;                      rente tipo di event listener esiste un’interfaccia
                                                              apposita, che lo sviluppatore deve implementare
import android.app.Activity;                                  per creare il suo gestore dell’evento. Ad esempio,
import android.os.Bundle;                                     l’interfaccia da implementare per gli eventi di clic è
import android.view.Gravity;                                  android.view. View.OnClickListener (interfaccia
import android.widget.LinearLayout;                           innestata nella classe View). Ciascuna interfaccia,
                                                              ovviamente, richiede l’implementazione di uno o
public class ButtonClickDemo1Activity extends Activity {      più metodi. Nel caso di OnClickListener, per prose-
      @Override                                               guire con l’esempio, il metodo da ridefinire è:
          public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);              public void onClick(View v) { ... }
             MyButton button = new MyButton(this);
            button.setText("Toccami!");                       Proviamo a ripetere l’esempio del paragrafo prece-
            LinearLayout layout = new LinearLayout(this);     dente, questa volta utilizzando il principio degli
            layout.setGravity(Gravity.CENTER);                event listener e, più nello specifico, l’interfaccia
            layout.addView(button);                           OnClickListener:

h t t p : / / w w w. i o p r o g r a m m o . i t
    32                                                                                                                    2010/ o g r G
                                                                                                                    Marzo And roi d pr 55am m in g
                                                Android: digitazione
                                         Android: tocco etocco e digitazione Android programming
                                  MOBILE �


                                    package it.ioprogrammo.buttonclickdemo2;                          android:layout_width="fill_parent"
                                                                                                      android:layout_height="fill_parent"
                                    import android.view.View;                                         android:gravity="center">
                                    import android.view.View.OnClickListener;                         <Button android:id="@+id/bottone01"
                                    import android.widget.Toast;                                      android:layout_width="wrap_content"
                                                                                                      android:layout_height="wrap_content"
                                    public class MyClickListener implements OnClickListener {         android:text="Toccami!" />
                                    ...                                                         </LinearLayout>


                                    Questa volta, invece di estendere Button e realiz-          L’attività, di conseguenza, andrebbe riscritta alla
                                    zare così un componente custom, abbiamo                     seguente maniera:
                                    semplicemente implementato un’interfaccia.
                                    Nel metodo onClick() abbiamo scritto il codice              package it.ioprogrammo.buttonclickdemo3;
                                    necessario per gestire l’evento di clic. Il parame-
                                    tro ricevuto dal metodo, nel caso specifico, rap-           import android.app.Activity;
                                    presenta l’oggetto View o derivato sul quale l’e-           import android.os.Bundle;
            NOTA
                                    vento è stato riscontrato. Affinché la classe               import android.widget.Button;
                                    MyClickListener venga utilizzata come gestore               public class ButtonClickDemo3Activity extends Activity {
                       FOCUS        dell’evento di clic su uno specifico widget, è              ...
     Un altro evento comune
     definito in View è quello      necessario registrarne un’istanza sul widget
   relativo al focus. Quando        stesso, servendosi del metodo setOnClick                    Dopo aver richiamato il layout definito nel file
   un widget riceve il focus,       Listener() citato in precedenza. Lo si può fare             XML, non si deve far altro che recuperare il bottone
 significa che è selezionato,       quando si allestisce o si richiama il layout dalla          al quale si vuole collegare l’evento e registrare su di
       e che tutti gli eventi di
                                    schermata. Ecco una Activity equivalente a quel-            esso il proprio listener personalizzato.
 digitazione saranno a esso
   rivolti. È possibile sapere      la del paragrafo precedente, ma che a differenza
 quando un widget riceve o          di quest’ultima utilizza un widget Button stan-
     perde il focus. Il metodo      dard insieme con l’event listener di poco sopra:
 per registrare il listener sul                                                                 COME SCRIVERE
                       widget è
setOnFocusChangeListener()
                                    package it.ioprogrammo.buttonclickdemo2;                    MENO CODICE
    , mentre l’interfaccia per                                                                  Qualcuno potrebbe obiettare che, con gli event
              implementarlo è       import android.app.Activity;                                listener, è comunque necessario creare una clas-
 View.OnFocusChangeListe            import android.os.Bundle;                                   se distinta per ciascun gestore previsto, con il
 ner. L’interfaccia richiede il     import android.view.Gravity;                                rischio di avere più codice dedicato alla cattura
                        metodo
                                    import android.widget.Button;                               degli eventi che non alla loro gestione. Esistono
onFocusChange(View view,
        boolean hasFocus). Il       import android.widget.LinearLayout;                         diversi trucchi applicabili con gli event listener
 parametro view è il widget                                                                     che aiutano ad evitare le situazioni di questo tipo.
      che ha subito l’evento,       public class ButtonClickDemo2Activity extends Activity {    Ve ne svelo un paio. Per realizzare un event liste-
           mentre il booleano       ...                                                         ner bisogna estendere un’interfaccia. Java non
        hasFocus indica se il
                                                                                                supporta l’ereditarietà multipla, e quindi una
  componente ha ricevuto il
focus (true) oppure se lo ha        In questa maniera non è stato necessario creare             classe può avere una sola super-classe. Questo
                 perso (false).     un componente custom: è stato sufficiente regi-             limite però non vale nel caso delle interfacce: una
                                    strare sul Button l’event listener realizzato               classe ne può implementare un numero qualsia-
                                    pocanzi, con la riga:                                       si. Ecco allora che, nel caso di GUI non troppo
                                                                                                complesse, si può fare che la Activity che control-
                                    button.setOnClickListener(new MyClickListener());           la lo schermo sia essa stessa event listener di uno
                                                                                                o più eventi, per uno o più widget. Mi spiego
                                    La tattica degli event listener, inoltre, si sposa          meglio con un esempio. Prendiamo in considera-
                                    meglio con la possibilità messa in campo da                 zione il seguente layout, come al solito da battez-
                                    Android di definire risorse e layout attraverso dei         zare main.xml:
                                    file XML (cfr. numero precedente). Il layout realiz-
                                    zato nell’attività mostrato poco sopra, ad esempio,         <?xml version="1.0" encoding="utf-8"?>
                                    potrebbe essere definito in un file XML indipen-            <LinearLayout xmlns:android="http://schemas
                                    dente. Chiamiamolo main.xml:                                                             .android.com/apk/res/android"
                                                                                                      android:orientation="vertical"
                                    <?xml version="1.0" encoding="utf-8"?>                            android:layout_width="fill_parent"
                                    <LinearLayout xmlns:android="http://schemas.                      android:layout_height="fill_parent"
                                                                 android.com/apk/res/android"         android:gravity="center">
                                          android:orientation="vertical"                              <Button android:id="@+id/bottone01"




   G 56 / Marzo 2010
                                                                                                                              h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                                   33
                            Android programming Android: tocco e digitazione
                                                      Android: tocco e digitazione MOBILE
                                                                                 �


      android:layout_width="wrap_content"                                 import android.os.Bundle;
      android:layout_height="wrap_content"                                import android.view.View;
      android:text="Bottone 1" />                                         import android.view.View.OnClickListener;
      <Button android:id="@+id/bottone02"                                 import android.widget.Button;
      android:layout_width="wrap_content"                                 import android.widget.Toast;
      android:layout_height="wrap_content"
      android:text="Bottone 2" />                                         public class ButtonClickDemo5Activity extends Activity {
</LinearLayout>                                                           ...


L’esempio è lievemente più complesso del prece-                           Così facendo non c’è bisogno di far implementa-
dente: qui i bottoni sono diventati due.                                  re alcuna interfaccia all’attività. La tecnica con-
Realizziamo un’attività che carichi questo layout e                       sente di scrivere davvero poco codice per inter-
gestisca gli eventi di clic su ambo i bottoni:                            cettare gli eventi, lasciando il programmatore                           NOTA
                                                                          libero di concentrarsi sulla logica della loro
package it.ioprogrammo.buttonclickdemo4;                                  gestione. Il più delle volte, è proprio quest’ultima           MODIFICATORI
                                                                                                                                         Quando si riceve un evento
                                                                          la tecnica da preferirsi.
                                                                                                                                         di digitazione, attraverso
import android.app.Activity;                                                                                                             l’istanza di KeyEvent, è
import android.os.Bundle;                                                                                                                possibile sapere se insieme
import android.view.View;                                                                                                                al tasto principale che
import android.view.View.OnClickListener;                                 PANORAMICA                                                     riguarda l’evento sono stati
import android.widget.Button;                                             SUGLI EVENTI                                                   attivati anche uno o più
                                                                                                                                         tasti modificatori. I tasti
import android.widget.Toast;                                              Ora che abbiamo imparato ad utilizzare gli event               modificatori, in Android,
                                                                          listener, la prima cosa da fare è chiedersi: quanti e          sono tre: ALT, SHIFT e SYM.
public class ButtonClickDemo4Activity extends Activity                    quali sono gli eventi che è possibile gestire? La              KeyEvent permette di
                                           implements OnClickListener {   risposta non è semplice: ogni widget ha i suoi even-           controllare lo stato dei tre
                                                                                                                                         modificatori attraverso i
...                                                                       ti e, di conseguenza, i suoi event listener. Anche in
                                                                                                                                         metodi booleani
                                                                          questo caso, quindi, la documentazione è una                   isAltPressed(),
In questo caso è la stessa attività a implementare                        risorsa fondamentale, che bisogna assolutamente                isShiftPressed() e
l’interfaccia OnClickListener, definendo di con-                          imparare a leggere. Soprattutto nel caso dei widget            isSymPressed().
seguenza il metodo onClick(). Non è stato dun-                            più particolari, quindi, dovrete cavarvela, altrimen-
que necessario creare una classe apposita.                                ti rischiamo di prolungare questo corso fino al
Inoltre l’event listener realizzato è stato adopera-                      2020! Insieme, però, possiamo prendere in esame i
to su due bottoni differenti (bottone01 e bot-                            tipi di eventi più universali e diffusi, riconosciuti e
tone02). È stato possibile farlo servendosi degli id                      gestibili su qualsiasi widget. A definirli, tanto per
assegnati ai due bottoni: all’interno del codice                          cambiare, è la madre di tutti i widget: la classe
del solo metodo onClick() realizzato, si è mostra-                        android.view.View. Ecco una panoramica degli
to un messaggio differente a seconda della sor-                           eventi più importanti:
gente dell’evento. Un’altra tecnica per risparmia-
re codice consiste nell’adoperare le classi inne-                         • Click. Lo abbiamo usato in tutti gli esempi pre-
state anonime di Java. È possibile fare qualcosa                            cedenti. Il metodo sul widget è setOnClick
di questo tipo:                                                             Listener(), e l’interfaccia per il gestore da imple-
                                                                            mentare è View.OnClickListener. Il metodo
button.setOnClickListener(new OnClickListener() {                           richiesto dall’interfaccia è onClick(View view),
      @Override                                                             che in parametro riporta il widget che ha subi-
      public void onClick(View view) {                                      to l’evento.
            // gestione evento                                                                                                           Fig. 2: Questa volta
      }                                                                   • Click lungo. Un evento che accade quando si                  bisogna gestire i clic su
});                                                                         clicca su un widget e si mantiene la pressione               due bottoni differenti
                                                                            per qualche istante. Il metodo per registrare l’e-
Di fatto si crea e si registra allo stesso tempo il                         vent listener è setOnLongClickListener(), e l’in-
gestore dell’evento di clic. Ci pensa il compilatore a                      terfaccia per il gestore è View.OnLongClick
separare la classe anonima innestata su un file                             Listener. Il metodo da implementare è onLong
.class differente. Riscriviamo allora l’esempio pre-                        Click(View view). Il metodo, come nel caso pre-
cedente secondo quest’altra tecnica:                                        cedente, riceve come parametro un riferimento
                                                                            al widget su cui si è prodotto l’evento. In più, il
package it.ioprogrammo.buttonclickdemo5;                                    metodo deve restituire un booleano per segna-
                                                                            lare se l’evento è stato completamente gestito
import android.app.Activity;                                                (true) oppure no (false).


h t t p : / / w w w. i o p r o g r a m m o . i t
    34                                                                                                                               Marzo 2010/o g r am m in g
                                                                                                                                          And roi d pr 57G
                                                Android: digitazione
                                         Android: tocco etocco e digitazione Android programming
                                  MOBILE �


                                    • Tocco. Un evento più generico dei due pre-                 <?xml version="1.0" encoding="utf-8"?>
                                      cedenti: serve per rilevare un tocco qualsiasi             <LinearLayout xmlns:android="http://schemas.
                                      su un componente. Il metodo per registrare il                                           android.com/apk/res/android"
                                      listener sul widget è setOnTouchListener(),                      android:orientation="vertical"
                                      mentre l’interfaccia per implementarlo è                         android:layout_width="fill_parent"
                                      View.OnTouch Listener. L’interfaccia richiede                    android:layout_height="fill_parent"
                                      il metodo onTouch(View view, MotionEvent                         android:gravity="center">
                                      event). Come nei casi precedenti, view è il                      <EditText android:id="@+id/eventArea"
                                      widget che ha subito l’evento. Il parametro di                   android:layout_width="wrap_content"
                                      tipo MotionEvent riporta invece i dettagli                       android:layout_height="wrap_content"
                                      dell’evento (tipo di azione, coordinate, dura-                   android:background="#990000"
                                      ta ecc.), come nel caso documentato nel                          android:textColor="#FFFFFF"
                                      primo esempio di oggi. Il metodo deve resti-                     android:width="200px"
                                      tuire un booleano per segnalare se l’evento è                    android:height="200px" />
                                      stato completamente gestito (true) oppure                        <TextView android:id="@+id/logArea"
                                      no (false).                                                      android:layout_width="wrap_content"
            L’AUTORE                                                                                   android:layout_height="wrap_content"
                                    • Digitazione. Un evento usato per segnalare                       android:text="Compi un evento sull'area
       Carlo Pelliccia lavora         la pressione o il rilascio di un tasto della                                                            rossa qui sopra" />
   presso 4IT (www.4it.it),
                                      tastiera hardware. Il metodo per registrare il             </LinearLayout>
 dove si occupa di analisi e
      sviluppo software per           listener sul widget è setOnKeyListener(),
piattaforme Java. Nella sua           mentre l’interfaccia per implementarlo è                   Il layout dispone, al centro del display, due compo-
 carriera di technical writer         View.OnKeyListener. L’interfaccia richiede il              nenti. C’è un EditText con sfondo di colore rosso e
       ha pubblicato cinque           metodo onKey( View view, int keyCode,                      dimensioni 200 x 200 pixel, che useremo per far
            manuali ed oltre
                                      KeyEvent event). Come nei casi precedenti,                 compiere all’utente delle operazioni di digitazione
    centocinquanta articoli,
molti dei quali proprio tra le        view è il widget che ha subito l’evento. Il                e di tocco. C’è poi un TextView, che useremo inve-
  pagine di ioProgrammo. Il           parametro keyCode riporta il codice associa-               ce per descrivere ogni evento riscontrato sul com-
 suo sito, che ospita anche           to al tasto premuto, mentre quello di tipo                 ponente precedente, dimostrando così di averlo
 diversi progetti Java Open           KeyEvent riporta ulteriori dettagli (tasto                 intercettato correttamente.
       Source, è disponibile
                                      pigiato, tasto rilasciato, eventuali modifica-             Andiamo ora a realizzare, mediante una Activity,
                 all’indirizzo
   www.sauronsoftware.it              tori e così via). Il metodo deve restituire un             quanto proposto:
                                      booleano per segnalare se l’evento è stato
                                      completamente gestito (true) oppure no                     package it.ioprogrammo.eventdemo;
                                      (false).
                                                                                                 import android.app.Activity;
                                    Siccome di esempi dedicati ai clic ne abbiamo già            import android.os.Bundle;
                                    visti diversi, proviamo ora a gestire i due eventi di        import android.util.Log;
                                    tocco e digitazione. Prepariamo il seguente layout,          import android.view.KeyEvent;
                                    da chiamare come al solito main.xml:                         import android.view.MotionEvent;
                                                                                                 import android.view.View;
                                                                                                 import android.view.View.OnTouchListener;
                                                                                                 import android.view.View.OnKeyListener;
                                                                                                 import android.widget.TextView;


                                                                                                 public class EventDemoActivity extends Activity {
                                                                                                 ...


                                                                                                 Sull’EditText vengono registrati due listener, uno
                                                                                                 per il tocco e l’altro per la digitazione. La tecnica
                                                                                                 usata per gli event listener è quella della classe ano-
                                                                                                 nima innestata. Gli eventi intercettati vengono esa-
                                                                                                 minati (attraverso le istanze di MotionEvent e
                                                                                                 KeyEvent) e descritte, sia nei log dell’applicazione
                                                                                                 (che potrete controllare comodamente usando
                                                                                                 Eclipse) sia nella TextView che ne dà immediato
                                    Fig. 3: L’applicazione intercetta gli eventi di digitazio-   riscontro all’utente.
                                    ne e tocco riscontrati sull’area rossa, e poi li descri-
                                    ve all’utente che li ha compiuti
                                                                                                                                                     Carlo Pelliccia



   G 58 / Marzo 2010
                                                                                                                               h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                                    35
                            Android programming Android: corso di programmazione
                                 MOBILE �             Android: corso di programmazione




ANDROID:
TUTTO SUI MENU
SETTIMO APPUNTAMENTO. ARGOMENTO DEL MESE SONO I MENU. LE APPLICAZIONI
ANDROID NE SUPPORTANO DIVERSI TIPI, CHE L’UTENTE PUÒ SFRUTTARE PER AZIONARE
COMANDI E IMPOSTARE LE OPZIONI. CONOSCIAMOLI E IMPARIAMO A PROGRAMMARLI




                                         I
                                             menu sono una parte importante di qualsiasi
                                             applicazione. Gli utenti sono abituati ad avere a
                                             che fare con il concetto di menu, al quale si rivol-
                                         gono ogni volta che vogliono cercare i comandi o
                                         modificare le opzioni delle loro applicazioni. Ciò
                                         risulta vero tanto nell’ambito dei software desktop,
                                         quanto in quello delle applicazioni mobili per cellu-
                                         lari e smartphone. Con questo articolo impareremo
    ❑ CD ❑ WEB                           a conoscere i menu previsti da Android, ponendo
    corso_android_pt7.zip
                                         particolare attenzione alle regole per la costruzione
                  cdrom.ioprogrammo.it
                                         di interfacce grafiche semplici ed efficaci, con menu
                                         concisi e facili da raggiungere e navigare.




                                         I MENU IN ANDROID
                                         In Android esistono tre differenti tipi di menu, che lo
                                         sviluppatore può collegare ad una Activity:

                                         • Options menu
                                           Sono i menu concepiti per raggruppare le opzioni
                                           ed i comandi di un’applicazione. Si dividono in
                                           due sotto-gruppi, icon menu ed expanded menu,
                                           descritti di seguito.

                                           • Icon menu                                              Fig. 1: L’icon menu utilizzato dal browser di Android
                                             Sono i menu con le opzioni principali di un’ap-
                                             plicazione. Vengono visualizzati nella parte              per esporre tutti i comandi e tutte le opzioni di
                                             bassa dello schermo quando si schiaccia il tasto          un’applicazione, le attività fanno ricorso agli
                                             “menu” del dispositivo. Vengono chiamati icon             expanded menu (letteralmente menu espansi).
                                             menu perché gli elementi contenuti al loro inter-         Quando ciò avviene, il menu principale, come
              REQUISITI
                                             no, in genere, sono delle grosse icone che l’uten-        suo ultimo tasto, presenta il bottone “altro”.
                                             te può selezionare con il polpastrello.                   Attivandolo si accede ad una lista aperta a tutto
Conoscenze richieste
   Java                                      Costituiscono il menu principale di ogni attività         schermo, che permette la consultazione delle
                                             e dovrebbero contenere sempre e solo le opzioni           altre opzioni di menu.
Software                                     più importanti. Questi menu sono di rapido
    Java SDK (JDK) 5+,
    Eclipse 3.3+                             accesso, ma soffrono per questo di alcune limi-        • Context menu
                                             tazioni: possono contenere al massimo sei ele-           I menu contestuali sono quelli che appaiono
                                             menti, e non è possibile inserire negli icon menu        quando si mantiene il tocco per qualche istante su
                                             elementi avanzati come le caselle di spunta              un widget che ne è dotato. Ad esempio nel brow-
Impegno
                                             (checkbox) e i bottoni radio.                            ser è possibile eseguire un tocco di questo tipo
¥                                                                                                     sopra ad un’immagine. Dopo qualche istante
Tempo di realizzazione
                                           • Expanded menu                                            verrà aperto un menu contestuale con alcune
                                             Quando il primo tipo di menu non è sufficiente           opzioni relative alla pagina corrente e all’immagi-

                                                                                                                              h t t p : / / w w w. i o p r o g r a m m o . i t
     G 50 / Aprile 2010
     36                                                                                                                                   And roi d pr o g r am m in g
                                                         Android: corso di programmazione Android programming
                                                   Android: corso di programmazione          � MOBILE


   ne selezionata, come ad esempio i comandi per                   una risorsa di tipo stringa memorizzata su file XML
   salvarla in locale e condividerla con gli amici.                esterno, nel secondo caso. Un controllo più granula-
   Come nel caso precedente, questo genere di                      re sugli elementi inseriti è reso possibile da queste
   menu si presenta come una lista a tutto schermo,                altre due varianti del metodo add():
   che può contenere numerose opzioni.
                                                                   public MenuItem add(int groupId, int itemId, int
• Submenu                                                                                         order, CharSequence title)
  Le applicazioni che dispongono di molti comandi                  public MenuItem add(int groupId, int itemId, int
  possono usufruire anche dei submenu. In pratica,                                                        order, int titleRes)
  in uno qualsiasi dei menu descritti in precedenza,
  è possibile inserire un elemento che, invece di                  In questo caso, oltre al titolo, è possibile specificare
  compiere un’azione diretta, va ad aprire un sotto-               altre tre proprietà di ciascun elemento del menu:
  menu, nel quale si possono presentare ulteriori
  possibilità di scelta.                                           • groupId
                                                                     Con questo valore è possibile assegnare l’elemen-
Nei prossimi paragrafi impareremo a programmare                      to ad un gruppo. Si può specificare un qualsiasi
tutti e tre i tipi di menu presentati.                               valore maggiore di zero (ovviamente deve essere
                                                                     lo stesso per due o più elementi che si intende
                                                                     assegnare al medesimo gruppo), oppure si può
                                                                     usare lo zero o la costante Menu.NONE se non si
OPTIONS MENU                                                         vuole assegnare l’elemento ad alcun gruppo.                 Fig. 2: L’expanded menu
                                                                                                                                 del browser di Android
Cominciamo dagli options menu che, come abbia-
mo detto, costituiscono il menu principale di qual-                • itemId
siasi applicazione. Il menu delle opzioni è un con-                  Con questo valore si assegna un identificativo
cetto strettamente legato a quello di singola attività.              all’elemento stesso. Questo identificativo torna
Ogni Activity, infatti, può avere un solo options                    utile in seguito, quando si vuole distinguere un
menu. La classe Activity dispone di un metodo defi-                  elemento da un altro. Come nel caso precedente,
nito al seguente modo:                                               bisogna usare un valore maggiore di zero affinché
                                                                     la caratteristica possa essere sfruttata. Se non si è
public boolean onCreateOptionsMenu(Menu menu)                        interessati all’assegnare un identificativo all’ele-
                                                                     mento, è sufficiente usare il valore zero o la
Questo metodo, nel ciclo di vita dell’attività, viene                costante Menu.NONE.
richiamato automaticamente dal sistema la prima
volta che l’utente preme il tasto “menu” del suo                   • order
dispositivo. L’argomento passato, un oggetto di tipo                 Se si vuole assegnare uno specifico ordine all’ele-
android.view.Menu, costituisce l’options menu ini-                   mento, è possibile in questo caso specificarlo
                                                                                                                                 Fig. 3: Il context menu
zialmente vuoto. Ridefinendo il metodo è possibile                   esplicitamente con un valore da uno in su.
                                                                                                                                 del browser di Android
intercettare queste chiamate e popolare così il menu                 Usando lo zero o la costante Menu.NONE si lascia            visualizzato quando si
fornito con le voci utili alla propria applicazione. Il              stabilire al sistema l’ordine dell’elemento nel             tiene il tocco per qual-
metodo onCreateOptionsMenu(), al termine dei pro-                    menu di appartenenza.                                       che secondo sopra ad
                                                                                                                                 un’immagine contenuta
pri compiti, deve restituire un booleano: true per
                                                                                                                                 in una pagina Web
rendere attivo il menu realizzato, false per dichiara-             Sperimentiamo subito quanto descritto finora.
re che l’attività non dispone di un menu, e quindi                 Realizziamo un’attività dimostrativa così formulata:
alla pressione del tasto “menu” del dispositivo non si
deve mostrare nulla. Programmando nel corpo del                    package it.ioprogrammo.menudemo01;
metodo, il proprio options menu può essere assem-                  import android.app.Activity;
blato servendosi dei metodi messi a disposizione                   import android.view.Menu;
dagli oggetti di tipo android.view.Menu. Aggiungere                public class MenuDemo01Activity extends Activity {
un elemento al menu è molto semplice, basta servir-                ...
si dei metodi:
                                                                   Abbiamo popolato il menu con sei semplici coman-
public MenuItem add(CharSequence title)                            di, etichettati rispettivamente “Comando 1”,
public MenuItem add(int titleRes)                                  “Comando 2”, “Comando 3” e così via. Installate l’ap-
                                                                   plicazione su un dispositivo e provate il suo menu.
Entrambi i metodi aggiungono un elemento al                        Dovreste ottenere un risultato simile a quello in fig.
menu. Il titolo dell’elemento (cioè la scritta che sarà            5. Come potete osservare, i sei elementi introdotti
mostrata per qualificarlo) può essere espressa con                 sono andati a costituire l’icon menu dell’attività.           Fig. 4: Un submenu del
una stringa, nel primo caso, o con il riferimento ad               Provate ora la seguente variante:                             browser di Android


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                              Aprile 2010/ 51 37
                                                                                                                                             G
                    Android programming Android: corso di programmazione
                         MOBILE �             Android: corso di programmazione


                                  package it.ioprogrammo.menudemo02;                        tare gli eventi di tocco riscontrati sugli elementi di
                                  import android.app.Activity;                              un options menu. La prima tecnica consiste nel
                                  import android.view.Menu;                                 ridefinire un metodo di Activity così definito:
                                  public class MenuDemo02Activity extends Activity {
                                  ...                                                       public boolean onOptionsItemSelected(MenuItem item)


                                  In questo caso i comandi sono nove. Lanciate l’atti-      Questo metodo viene richiamato automaticamente
                                  vità e verificate cosa accade. Mentre nel caso prece-     ogni volta che uno degli elementi dell’options menu
                                  dente tutti e sei i comandi previsti sono diventati       dell’attività viene selezionato dall’utente. Lo specifi-
           NOTA
                                  parte dell’icon menu dell’attività, ora le cose sono      co elemento selezionato, naturalmente, è quello
                                  andate diversamente. Come accennato in apertura,          riportato in argomento, mentre il valore di ritorno
               ANDROID            un icon menu può contenere al massimo sei ele-            serve per indicare al sistema se l’evento è stato gesti-
              2.1 (API 7)
 Anche questo mese c’è da         menti, come nel caso del primo esempio. Ora che gli       to (true) oppure no (false). Ridefinendo il metodo e
        segnalare una nuova       elementi sono diventati nove, il sistema ha posizio-      applicando dei filtri sull’identificativo dell’elemento
  release di Android, la 2.1.     nato nell’icon menu solo i primi cinque del lotto. Il     segnalato (è possibile recuperarlo con il metodo
Le API vengono avanzate al        sesto spazio disponibile nell’icon menu è stato auto-     getId() di MenuItem) è possibile riconoscere e gesti-
    livello 7. Si tratta di una
                                  maticamente occupato con un elemento di tipo              re la specifica azione eseguita dall’utente. Ecco un
         release minore, e le
     modifiche per quel che       “altro”, che lavora come pulsante d’accesso per l’ex-     esempio che mostra un avviso differente in base alla
                    riguarda la   panded menu dell’attività. In quest’ultimo sono           voce di menu selezionata:
      programmazione sono         stati inseriti i restanti quattro comandi. Gli elementi
       poche. Se volete dare      che confluiscono nell’icon menu possono utilizzare        package it.ioprogrammo.menudemo04;
  un’occhiata al changelog:
                                  delle icone al posto del testo. Usufruire di questa       ...
 http://developer.android.
com/sdk/android-2.1.html          funzionalità è molto semplice. Per prima cosa dove-       public class MenuDemo04Activity extends Activity {
                                  te fare caso al fatto che i metodi add() di Menu resti-   ...
                                  tuiscono un oggetto di tipo android.view.MenuItem.
                                  Come è facile intuire, l’oggetto restituito rappresen-    Questo stralcio di codice mette in atto una tecnica
                                  ta l’elemento appena introdotto nel menu. Questo          consigliata: memorizzare gli identificativi degli ele-
                                  genere di oggetti dispone di metodi che permettono        menti del menu con delle costanti. In questo modo
                                  il controllo dell’elemento. Fra questi segnaliamo i       gli ID risultano più leggibili e si è meno inclini a
                                  seguenti:                                                 commettere errori di battitura o distrazione. Una
                                                                                            seconda tecnica per la gestione degli eventi consiste
                                  public MenuItem setIcon(Drawable icon)                    nell’utilizzare il seguente metodo di MenuItem:
                                  public MenuItem setIcon(int iconRes)
                                                                                            public MenuItem setOnMenuItemClickListener
                                  Ambo i metodi servono per aggiungere un’icona                                (MenuItem.OnMenuItemClickListener
                                  all’elemento. Si può usare un oggetto graphics.draw-                                         menuItemClickListener)
                                  able.Drawable, caricato o realizzato in precedenza,
                                  oppure il riferimento ad un’immagine conservata           La tecnica richiama le logiche di gestione degli even-
Fig. 5: Un semplice               nella directory res/drawable del progetto. Una volta      ti che abbiamo conosciuto il mese scorso. L’interfac-
icon menu, con sei                impostata un’icona su un elemento, questa sarà            cia MenuItem.OnMenuItemClickListener richiede l’im-
comandi testuali                  mostrata solo se l’elemento è parte dell’icon menu.       plementazione del metodo:
                                  Ecco un esempio che dimostra la funzionalità:
                                                                                            public boolean onMenuItemClick(MenuItem item)
                                  package it.ioprogrammo.menudemo03;
                                  ...                                                       Il metodo viene richiamato quando l’elemento è
                                  public class MenuDemo03Activity extends Activity {        selezionato dall’utente. Ecco un esempio analogo al
                                  ...                                                       precedente, ma basato su questa seconda tecnica di
                                                                                            gestione degli eventi:
                                  Affinché l’esempio funzioni correttamente, è neces-
                                  sario disporre delle immagini play, pause e stop nella    package it.ioprogrammo.menudemo05;
                                  directory res/drawable del progetto. Nel CD-Rom           ...
Fig. 9: Sono stati
                                  allegato alla rivista troverete tutto ciò di cui avrete   public class MenuDemo05Activity extends Activity {
aggiunti nove comandi
al menu. I primi cinque           bisogno. Una volta fatta funzionare l’attività, il suo    ...
sono entrati a far parte          icon menu sarà come quello mostrato in Fig. 7. Ora
dell’icon menu, mentre i          che abbiamo imparato a disporre gli elementi nel-         La classe Activity, infine, dispone di altri due metodi
restanti quattro sono
                                  l’options menu, impariamo anche come gestire gli          collegati alla gestione del suo options menu:
stati posizionati nell’ex-
panded menu dell’atti-            eventi di attivazione di ciascuno degli elementi
vità                              introdotti. Esistono un paio di maniere per intercet-     • public boolean onPrepareOptionsMenu(Menu menu)


   G 52 / Aprile 2010
                                                                                                                      h t t p : / / w w w. i o p r o g r a m m o . i t
   38                                                                                                                             And roi d pr o g r am m in g
                                                         Android: corso di programmazione Android programming
                                                   Android: corso di programmazione          � MOBILE


   Viene richiamato quando l’options menu sta per                    gendo elementi al parametro menu. Il terzo argo-
   essere     visualizzato.    Infatti  il   metodo                  mento, menuInfo, viene usato solo in alcuni casi
   onCreateOptionsMenu(), usato in tutti gli esempi                  che esamineremo in futuro, come ad esempio
   precedenti, viene richiamato solo la prima volta                  quando si ha a che fare con le liste.
   che il menu deve essere mostrato. Se si intende
   modificare il menu costruito in precedenza, si può              • public boolean onContextItemSelected(MenuItem
   ridefinire questo secondo metodo. Gli oggetti                     item)
   Menu, a tal proposito, dispongono di una serie di                 Richiamato quando un elemento di un context
   metodi che permettono di recuperare, modificare                   menu viene selezionato.
   e rimuovere gli elementi introdotti al suo interno              • public void onContextMenuClosed(Menu menu)
   in precedenza. Anche se non è un caso molto                       Richiamato quando il menu contestuale viene
   comune, quindi, Android permette lo sviluppo di                   chiuso.
   options menu dinamici, che cambiano in base                                                                                       NOTA
   allo stato dell’applicazione.                                   Gli oggetti android.view.ContextMenu dispongo-
                                                                   no di tutti i metodi già visti con gli oggetti Menu.     LA REGOLA
• public void onOptionsMenuClosed(Menu menu)                       Fate però attenzione al fatto che gli elementi dei       DEI TRE CLIC
                                                                                                                            Una vecchia regola di
  Viene richiamato quando l’options menu, dopo                     menu contestuali non supportano né le icone né           usabilità dice che l’utente
  essere stato visualizzato, viene chiuso.                         le scorciatoie da tastiera (cfr. box laterale).          deve sempre poter trovare
                                                                   In compenso gli oggetti ContextMenu si specia-           quel che cerca con al
• public void openOptionsMenu()                                    lizzano attraverso i seguenti metodi:                    massimo tre clic. Se non ci
  Apre il menu automaticamente, senza che sia                                                                               riesce, l’utente inizia a
                                                                                                                            provare frustrazione.
  necessario premere il tasto “menu” del dispositi-                • public ContextMenu setHeaderTitle(CharSe-              Questa regola è stata
  vo.                                                                quence title)                                          inizialmente concepita per
                                                                     public ContextMenu setHeaderTitle(int titleRes)        il Web ma, di fatto, oggi
                                                                     Associa un titolo al menu contestuale, che sarà        può essere applicata anche
                                                                     mostrato nell’intestazione del menu.                   alle applicazioni mobili e
                                                                                                                            desktop di tipo non
CONTEXT MENU                                                                                                                professionale e dedicate ad
I menu contestuali permettono di associare partico-                • public ContextMenu setHeaderIcon(Drawable              un pubblico quanto più
lari opzioni o comandi ai singoli widget di un’atti-                 icon)                                                  ampio possibile. I menu di
vità. La creazione e l’utilizzo dei context menu sono                public ContextMenu setHeaderIcon(int icon-             Android, è evidente, sono
molto simili a quelli dell’options menu.                             Res)                                                   stati concepiti tenendo a
                                                                                                                            mente la regola.
La prima cosa che si deve fare è dichiarare che uno o                Associa un’icona al menu contestuale, che sarà         Per approfondire:
più widget dell’attività devono disporre di un menu                  mostrata nell’intestazione del menu.                   http://en.wikipedia.org/wi
contestuale. Lo si può fare con il metodo                                                                                   ki/Three-click_rule
registerForContextMenu(View view) di Activity.                     • public ContextMenu setHeaderView(View view)
Ad esempio, per dotare un bottone di un menu con-                    Imposta l’oggetto view come intestazione del
testuale si deve fare così:                                          menu, sostituendo l’icona ed il titolo dei meto-
                                                                     di precedenti.
Button mioBottone = new Button(this);
// …                                                               • public void clearHeader()
registerForContextMenu(mioBottone);                                  Ripulisce l’intestazione del menu.

Se il widget è stato dichiarato in un XML di layout, lo            Realizziamo insieme il seguente esempio di codice:
si può caricare attraverso il suo identificativo:
                                                                   package it.ioprogrammo.menudemo06;
View mioWidget = findViewById(R.id.mioWidgetId);                   ...
// ...                                                             public class MenuDemo06Activity extends Activity {
registerForContextMenu(mioBottone);                                ...
Fatto ciò, è possibile ridefinire uno o più metodi di                                                                       Fig. 7: Le icone degli
Activity in modo da generare e gestire il menu con-                Si tratta di un’attività che dispone di due bottoni,     elementi vengono
testuale. Questi metodi sono:                                      tutti e due collegati ad un menu contestuale.            mostrate nell’icon
                                                                   L’esempio mostra come registrare i widget per il         menu.
• public void onCreateContextMenu(ContextMenu                      menu contestuale, come creare menu distinti per
  menu,View v, ContextMenu.ContextMenuInfo men-                    widget differenti e come gestire gli eventi dei
  uInfo)                                                           menu contestuali. A proposito di eventi: anche
  Questo metodo viene richiamato ogni volta che il                 nel caso dei context menu è possibile sfruttare la
  menu contestuale per il widget v deve essere                     tecnica di gestione alternativa basata sugli ogget-
  mostrato. Il menu deve essere costruito aggiun-                  ti OnMenuItemClickListener.


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                           Aprile 2010/ 53G
                                                                                                                                         39
                    Android programming Android: corso di programmazione
                         MOBILE �             Android: corso di programmazione


                                  SUBMENU                                                   public void setGroupVisible(int groupId, boolean visible)
                                  Aggiungere sotto-menu ad un options menu o ad un
                                  context menu è possibile grazie ai seguenti metodi,       Più particolare il seguente metodo:
                                  disponibili per oggetti Menu e ContextMenu:
                                                                                            public void setGroupCheckable(int group, boolean
                                  • public SubMenu addSubMenu(CharSequence title)                                        checkable, boolean exclusive)
                                  • public SubMenu addSubMenu(int titleRes)
                                  • public SubMenu addSubMenu(int groupId, int              Questo metodo rende checkable tutti gli elementi di
                                    itemId, int order, CharSequence title)                  un gruppo. Quando un elemento è checkable, si
                                  • public SubMenu addSubMenu(int groupId, int              comporta come un interruttore che può essere acce-
                                    itemId, int order, int titleRes)                        so (selezionato) o spento (non selezionato). Se il
                                                                                            parametro exclusive è false, gli elementi si compor-
          NOTA
                                  Questi metodi assomigliano molto ai metodi add()          teranno come delle checkbox: quindi sarà possibile
                                  per l’aggiunta di un comune elemento, ed infatti          selezionarne anche due o più contemporaneamen-
           ABILITARE              funzionano alla stessa maniera. La differenza è che       te. Se exclusive è true, invece, gli elementi del gruppo
      E DISABILITARE
        GLI ELEMENTI              l’elemento inserito, una volta selezionato, causerà       si comporteranno come dei bottoni radio. Si può
  Gli elementi di un menu         l’apertura di un sotto-menu. Cosa sarà mostrato nel       selezionare o deselezionare un elemento con il
possono essere disabilitati       sotto-menu possiamo stabilirlo con l’oggetto              metodo di MenuItem così definito:
        e successivamente         android.view.SubMenu, restituito dai metodi
  riabilitati servendosi del
                                  addSubMenu(). Anche in questo caso avremo a               public MenuItem setChecked(boolean checked)
       seguente metodo di
                  MenuItem:       disposizione tutti i metodi di Menu, ed avremo a
           public MenuItem        disposizione anche dei metodi come quelli di              Se un elemento è selezionato oppure no, invece, lo si
       setEnabled(boolean         ContextMenu per la definizione di un’intestazione         può sapere chiamando:
                    enabled)      del menu. In effetti i submenu somigliano molto ai
    Quando un elemento è
                                  context menu:                                             public boolean isChecked()
  disabilitato, l’utente non
può selezionarlo: come se
                non ci fosse.     package it.ioprogrammo.menudemo07;                        Ecco un esempio che dimostra questa funzionalità:
                                  ...
                                  public class MenuDemo07Activity extends Activity {        package it.ioprogrammo.menudemo08;
                                  ...                                                       ...
                                                                                            public class MenuDemo08Activity extends Activity {
                                                                                            ...


          L’AUTORE                GRUPPI DI ELEMENTI
                                  Gli elementi di un menu possono essere riuniti in
       Carlo Pelliccia lavora     dei gruppi. Due o più elementi sono nello stesso          MENU IN SALSA XML
   presso 4IT (www.4it.it),       gruppo se, quando li si è aggiunti, si è usato lo stes-   I menu, proprio come i layout, possono essere
   dove si occupa di analisi      so valore groupId. Ad esempio:                            definiti via XML. Per farlo si usa la speciale car-
    e sviluppo software per
           piattaforme Java.                                                                tella res/menu. I file XML al suo interno usano i
           Nella sua carriera     menu.add(1, MENUITEM_COMANDO_1, 1, "Comando 1");          tag <menu>, <group> e <item> per definire i
       di technical writer ha     menu.add(1, MENUITEM_COMANDO_2, 1, "Comando 2");          menu in modo dichiarativo. Eclipse, attraverso il
 pubblicato cinque manuali        menu.add(Menu.NONE, MENUITEM_COMANDO_3, 3,                plug-in per lo sviluppo Android, dispone di un
    ed oltre centocinquanta                                               "Comando 3");     plug-in per l’editing visuale di questi file. I menu
      articoli, molti dei quali
     proprio tra le pagine di                                                               XML possono essere caricati attraverso la classe
  ioProgrammo. Il suo sito,       “Comando 1” e “Comando 2” appartengono al                 android.view.MenuInflater ed il suo metodo
   che ospita anche diversi       gruppo con groupId 1, mentre “Comando 3” non              inflate(int menuRes, Menu menu). Terminiamno
progetti Java Open Source,        fa parte di alcun gruppo (il suo groupId è                con il caso di caricare il menu /res/menu/
   è disponibile all’indirizzo    Menu.NONE). I gruppi di elementi permettono               menu1.xml come options menu di un’attività:
  www.sauronsoftware.it
                                  di velocizzare alcune operazioni. Ad esempio se
                                  si intende abilitare o disabilitare tutti gli elemen-     @Override
                                  ti di un gruppo, è sufficiente richiamare il meto-        public boolean onCreateOptionsMenu(Menu menu)
                                  do di Menu così definito:                                 {
                                                                                                  MenuInflater inflater = new MenuInflater(this);
                                  public void setGroupEnabled(int groupId, boolean                inflater.inflate(R.menu.menu1, menu);
                                                                                enabled)          return true;
                                                                                            }
                                  Gli elementi di un gruppo possono essere resi visibi-
                                  li o invisibili chiamando il metodo:                                                                         Carlo Pelliccia



  G 54 / Aprile 2010
                                                                                                                         h t t p : / / w w w. i o p r o g r a m m o . i t
  40                                                                                                                                 And roi d pr o g r am m in g
                                                      Android: corso di programmazione
                                         MOBILE � corso di programmazione
                                           Android:                               Android programming




NOTIFICHE E FINESTRE
DI DIALOGO
OTTAVO APPUNTAMENTO. QUESTO MESE INCREMENTEREMO L’INTERATTIVITÀ
DELLE NOSTRE APPLICAZIONI, DOTANDOLE DELLA POSSIBILITÀ DI EMETTERE
DEGLI AVVISI E DI INTERROGARE L’UTENTE ATTRAVERSO LE FINESTRE DI DIALOGO




                                           N
                                                    ei mesi passati abbiamo già appreso               sa), il messaggio da mostrare (come stringa, nel
                                                    numerose tecniche per dialogare con chi           primo caso, o come riferimento a risorsa esterna, nel
                                                    utilizza l’applicazione: tra widget, eventi e     secondo) e la durata del messaggio. Non è possibile
                                           menu siamo già in grado di costruire applicazioni          specificare quanti secondi, esattamente, il messag-
                                           interattive. Ci sono comunque altri due strumenti          gio dovrà restare visibile. Si può soltanto dire se il
                                           che non possono assolutamente mancare nel                  messaggio deve durare poco o tanto. Per farlo si deve
                                           nostro armamentario: sono i cosiddetti toast e le          usare come argomento duration una fra le due
                                           finestre di dialogo. I primi servono per segnalare         costanti Toast.LENGTH_SHORT (durata breve) o
    ❑ CD ❑ WEB                             delle notifiche, mentre le seconde possono essere          Toast.LENGTH_ LONG (durata lunga). Ecco un
    corso_android_pt7.zip
                                           usate sia per emettere un output sia per ricevere          esempio:
                  cdrom.ioprogrammo.it
                                           un input.
                                                                                                      Toast toast = Toast.makeText(this, "Questo è un toast",
                                                                                                                                            Toast.LENGTH_LONG);


                                           UN TOAST COME AVVISO                                       Una volta creato, il toast può essere mostrato chia-
                                           Un toast è un avviso mostrato per qualche istante in       mandone il metodo show():
                                           sovraimpressione sullo schermo. Le notifiche toast
                                           vanno usate per brevi messaggi testuali. Insomma,          toast.show();
                                           informazioni del tipo “impostazioni salvate”, “opera-
                                           zione eseguita” e simili. I messaggi toast rimangono       Altri metodi degli oggetti Toast permettono di impo-
                                           sullo schermo per qualche istante e poi il sistema li      stare ulteriori proprietà dell’avviso. Si consideri ad
                                           rimuove automaticamente: non c’è alcuna intera-            esempio il metodo:
                                           zione con l’utente. La classe di riferimento per la
                                           gestione dei messaggi toast è android.widget.Toast.        public void setGravity(int gravity, int xOffset, int
                                           A disposizione ci sono i seguenti due metodi statici:      yOffset)

                                           ●   public static Toast makeText(Context context,          Con questo metodo si può impostare in quale ango-
                                               CharSequence text, int duration)                       lo dello schermo far apparire il messaggio (gravity,
                                           ●   public static Toast makeText(Context context, int      cfr. ioProgrammo 146), specificando anche il disco-
                                               resId, int duration)                                   stamento dai bordi laterali (xOffset) e da quelli verti-
                                                                                                      cali (yOffset). Ad esempio:
              REQUISITI
                                           Entrambi i metodi costruiscono un messaggio toast
                                           testuale. I parametri da fornire sono, rispettivamen-      toast.setGravity(Gravity.TOP | Gravity.LEFT, 10, 10);
  Conoscenze richieste
     Java                                  te, il contesto applicativo (ad esempio l’attività stes-
                                                                                                      Questo avviso sarà mostrato in alto a sinistra, sco-
  Software                                                                                            stato di 10 pixel dai bordi. Si possono anche creare
      Java SDK (JDK) 5+,
      Eclipse 3.3+                                                                                    dei messaggi toast che, invece di mostrare del sem-
                                                                                                      plice testo, facciano uso di immagini o di altri widget
                                                                                                      al loro interno. In tal caso, invece di passare per i
                                                                                                      metodi statici makeToast(), si usa il costruttore della
  Impegno
                                                                                                      classe, che vuole in argomento il contesto dell’appli-
¥                                                                                                     cazione:
 Tempo di realizzazione                    Fig. 1: Ecco come appare un messaggio toast nell’in-
                                           terfaccia di Android                                       Toast toast = new Toast(this);


                                                                                                                                 h t t p : / / w w w. i o p r o g r a m m o . i t
     G 62 / Maggio 2010
A n d ro id p r o g r a m m ing                                                                                                                                     41
                                           Android: corso di programmazione
                            Android programming                                   � MOBILE
                                                        Android: corso di programmazione


La durata, in questo caso, la si può stabilire con        FINESTRE DI DIALOGO
setDuration():                                            Le finestre di dialogo sono dei riquadri che è possi-
                                                          bile aprire sopra l’attività corrente. Quando una
toast.setDuration(Toast.LENGTH_LONG);                     finestra di dialogo compare, l’attività da cui dipende
                                                          viene bloccata, e l’utente deve necessariamente
Il contenuto del toast, adesso, può essere del testo,     interagire con la finestra di dialogo per farvi ritorno.
come nel caso precedente:                                 L’esempio tipico è la finestra di conferma, che
                                                          domanda all’utente se vuole proseguire con una
toast.setText("messaggio di testo");                      certa operazione. L’utente, quando tale finestra
                                                          compare, non può far altro che scegliere tra l’opzio-
Esiste anche una seconda variante di setText() che        ne per proseguire e quella per annullare. Finché la
permette l’utilizzo delle stringhe esterne:               scelta non viene espressa, l’attività sottostante rima-
                                                          ne bloccata e non può essere ripresa.
toast.setText(R.string.messaggio_esterno);                A differenza dei toast, quindi, le finestre di dialogo
                                                          sono sia bloccanti sia interattive. Per questo motivo
Per un toast graficamente più ricco, invece, si può       la loro gestione risulta lievemente più complessa.
usare il metodo setView(View view), che imposta il        L’astrazione di base cui far riferimento è la classe
widget da visualizzare all’interno della notifica in      android.app.Dialog, che definisce mediante i suoi                       NOTA
sostituzione del testo. Ad esempio un’icona:              metodi cosa una finestra di dialogo può fare e come
                                                          può essere manipolata. Nei prossimi paragrafi la              SDK TOOLS R5
ImageView image = new ImageView(this);                    approfondiremo più nello specifico. Adesso, invece,           E ADT 0.9.6
image.setImageResource(R.drawable.mia_icona);             concentriamoci sul ciclo di vita delle finestre di dia-       A metà marzo è stata
                                                                                                                        rilasciata la versione r5 dei
Toast toast = new Toast(this);                                                                                          tool di sviluppo Android,
                                                                                                                        per Windows, Linux e
toast.setGravity(Gravity.CENTER, 0, 0);
                                                                                                                        MacOS X. Per sviluppare in
toast.setDuration(Toast.LENGTH_LONG);                                                                                   ambiente Eclipse con la
toast.setView(image);                                                                                                   nuova versione del kit è
toast.show();                                                                                                           necessario aggiornare il
                                                                                                                        proprio plug-in ADT alla
                                                                                                                        versione 0.9.6. Gli indirizzi
Un layout XML esterno può essere caricato, proprio
                                                                                                                        di riferimento sono:
sotto forma di oggetto View, passando attraverso un
oggetto android.view.LayoutInflater. Ogni attività ne                                                                   http://developer.android.c
mette a disposizione un’istanza:                                                                                        om/sdk/index.html
                                                          Fig. 3: Una richiesta di conferma all’interno di una
                                                          finestra di dialogo                                           http://developer.android.c
LayoutInflater inflater = getLayoutInflater();
                                                                                                                        om/sdk/eclipse-adt.html
View view = inflater.inflate(R.layout.toast_xml, null);


Questo significa che toast di maggiore complessità        logo, e sulla maniera che dovremo adoperare per
possono essere creati con la più agevole sintassi di      richiamarle e mostrarle.
XML, per essere poi caricati dinamicamente quando         La classe Activity fornisce un metodo così definito:
occorre mostrarli.
Nel CD-Rom allegato alla rivista troverete degli          public final void showDialog(int id)
esempi completi di utilizzo delle notifiche toast.
                                                          Possiamo richiamare questo metodo ogni volta che
                                                          dobbiamo aprire e mostrare una finestra di dialogo.
                                                          Il parametro id simboleggia quale specifica finestra
                                                          di dialogo l’attività deve mostrare. Il valore è arbitra-
                                                          rio, nel senso che è nostro compito creare le finestre
                                                          di dialogo ed assegnargli degli identificativi. La pras-
                                                          si consiglia di usare delle costanti interne alla classe
                                                          dell’attività.
                                                          Mi spiego meglio attraverso un esempio. Facciamo il
                                                          caso che la nostra attività faccia uso di due finestre
                                                          di dialogo, una per emettere un avviso di errore ed
                                                          una per richiedere una conferma. La miglior cosa da
Fig. 2: Un toast di maggiore complessità, con icona       fare, in casi come questo, è aggiungere due costanti
e testo, costruito a partire da una definizione di        all’attività, con nomi e valori arbitrari ma univoci. Ad
layout esterna, in formato XML
                                                          esempio:

h t t p : / / w w w. i o p r o g r a m m o . i t
    42                                                                                                                  2010/ 63 G
                                                                                                                 Maggio And roi d pr o g r am m in g
                                               Android: corso di programmazione
                                  MOBILE � corso di programmazione
                                    Android:                               Android programming


                                    private static final int DIALOG_ERROR_ID = 1;                 @Override
                                    private static final int DIALOG_CONFIRM_ID = 2;               protected void onPrepareDialog(int id, Dialog dialog) {
                                                                                                      switch (id) {
                                    Quando dovremo mostrare l’avviso di errore, dun-                  ...
                                    que, chiameremo:
                                                                                                  È importate sapere che il metodo onCreateDialog()
                                    showDialog(DIALOG_ERROR_ID);                                  per uno specifico id viene richiamato solo la prima
                                                                                                  volta che la corrispondente finestra di dialogo deve
                                    Analogamente, per la richiesta di conferma, dovre-            essere mostrata. La seconda volta che la stessa fine-
             NOTA
                                    mo fare:                                                      stra dovrà essere mostrata, il sistema farà riuso del-
                                                                                                  l’istanza già esistente. Se bisogna inizializzare l’i-
              TOAST: NON            showDialog(DIALOG_CONFIRM_ID);                                stanza in maniera differente dalla volta precedente,
              SOLO DALLE
                 ATTIVITÀ                                                                         quindi, non resta che farlo ridefinendo onPrepare
  I messaggi toast possono          Adesso viene da chiedersi: come fa Android a sapere           Dialog() e adottando lo schema proposto sopra. Una
        essere mostrati non         quali finestre corrispondano effettivamente ai due            volta che una finestra di dialogo viene aperta, ci
   soltanto dalle attività, ma      interi indicati? Ed infatti, allo stato attuale delle cose,   sono due maniere per chiuderla. In primo luogo la
        anche da altri tipi di
                                    Android non lo sa: siamo noi a dover svolgere le              può chiudere l’utente servendosi del tasto “back” del
 applicazioni Android, come
                     i servizi.     associazioni. Per farlo dobbiamo ridefinire il meto-          suo dispositivo. Non sempre è possibile farlo, dipen-
                                    do di Activity avente firma:                                  de dal tipo e dalle impostazioni della specifica fine-
                                                                                                  stra di dialogo. Quando è possibile farlo si dice che la
                                    protected Dialog onCreateDialog(int id)                       finestra è cancelable (cioè cancellabile). Via codice,
                                                                                                  invece, è sempre possibile chiudere e terminare
             NOTA
                                    Android richiama questo metodo ogni volta che                 qualsiasi finestra di dialogo. Lo si può fare invocan-
                                    deve creare una finestra di dialogo. La finestra che          do il metodo di Activity così definito:
                  INSERIRE          deve essere creata è identificata dal parametro id.
                  UNA DATA
Altre due finestre di dialogo       Ridefinendo il metodo dobbiamo riconoscere l’i-               public final void dismissDialog(int id)
     previste dalla libreria di     dentificativo fornito, costruire la finestra di dialogo
                Android sono        corrispondente e restituirla sotto forma di oggetto           Ad esempio:
          DatePickerDialog e        android.app.Dialog. Lo schema consigliato è il
           TimePickerDialog,
                                    seguente:                                                     dismissDialog(DIALOG_ERROR_ID);
    entrambe nel pacchetto
   android.app. Come il loro
         nome lascia intuire,       @Override                                                     La finestra dismessa viene chiusa e nascosta. Come
servono per far selezionare         protected Dialog onCreateDialog(int id) {                     spiegato prima, però, un riferimento all’oggetto
    all’utente una data o un            Dialog dialog;                                            Dialog che la rappresenta viene conservato all’inter-
                        orario.
                                        switch (id) {                                             no dell’attività, in modo che l’istanza possa essere
                                        ...                                                       riusata nel caso in cui la stessa finestra debba essere
                                                                                                  nuovamente mostrata. In realtà è possibile far
                                    In breve, si utilizza un costrutto switch per associare       dimenticare del tutto la finestra di dialogo, serven-
                                    degli oggetti Dialog ai loro corrispettivi identificativi     dosi al posto di dismissDialog() del metodo:
                                    numerici. Nel codice di esempio si fa riferimento ai
                                    due        metodi          createErrorDialog()          e     public final void removeDialog(int id)
                                    createConfirmDialog(), che sono dei metodi custom
                                    che lo sviluppatore crea a proprio piacimento per             In questo caso l’istanza della corrispondente fine-
                                    generare le differenti finestre di dialogo di cui ha          stra di dialogo viene eliminata. Se la finestra dovrà
                                    bisogno.                                                      essere mostrata di nuovo, sarà necessario ricrearla
                                    Dopo che la specifica finestra di dialogo è stata crea-       utilizzando nuovamente onCreateDialog(). La prassi
                                    ta, Android prima di mostrarla richiama il seguente           dunque è invocare dismissDialog() per le finestre di
                                    metodo di Activity:                                           dialogo usate frequentemente, removeDialog() per
                                                                                                  chiudere quelle mostrate raramente. Ora che abbia-
                                    protected void onPrepareDialog(int id, Dialog dia-            mo le idee chiare sul ciclo di vita delle finestre di dia-
                                    log)                                                          logo, impareremo come costruire e amministrare
                                                                                                  una finestra di dialogo. Poche volte si usa diretta-
                                    I due parametri corrispondono, rispettivamente,               mente la classe Dialog: nella stragrande maggioran-
                                    all’identificativo della finestra e all’oggetto Dialog        za dei casi si fa prima ad usare una delle sue sotto-
                                    costruito nel passaggio precedente. Lo sviluppatore           classi messe a disposizione dalla libreria di Android.
                                    può opzionalmente ridefinire questo metodo per                Classi      come      android.app.AlertDialog            e
                                    inizializzare la finestra di dialogo con dei comandi          android.app.ProgressDialog, infatti, coprono il 99%
                                    specifici. Il modello, questa volta, è il seguente:           delle esigenze. Andiamo a conoscerle.


    G 64 / Maggio 2010
                                                                                                                             h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                                  43
                                           Android: corso di programmazione
                            Android programming                                   � MOBILE
                                                        Android: corso di programmazione


ALERTDIALOG                                                                     mo dunque in modo che la finestra di dialogo venga
Il primo tipo di finestra di dialogo che studieremo è                           chiusa quando l’utente tocca il bottone. Semplice,
android.app.AlertDialog. È quella utile per mostrare                            vero? Altrettanto semplice, a questo punto, è creare
un avviso o per chiedere qualcosa all’utente, come                              una richiesta di conferma, come quella discussa in
una conferma o la selezione di un elemento da una                               apertura di paragrafo:
lista. Cominciamo dal più semplice dei casi: voglia-
mo notificare un evento e vogliamo essere sicuri che                            AlertDialog.Builder builder = new
l’utente ne prenda atto. Un messaggio toast, in que-                                                               AlertDialog.Builder(this);
sto caso, non andrebbe bene: potrebbe scomparire                                builder.setTitle("Conferma");
prima che l’utente lo noti. Useremo allora una fine-                            builder.setMessage("Vuoi proseguire con l'operazione?");
stra di dialogo in grado di bloccare l’applicazione fin                         builder.setCancelable(false);
quando l’utente non noterà ed accetterà il messag-                              builder.setPositiveButton("Prosegui", new
gio. Il codice per farlo è molto semplice:                                                              DialogInterface.OnClickListener() {               NOTA
                                                                                      @Override
AlertDialog.Builder builder = new                                                     ...                                                       NOTIFICHE NELLA
                                                   AlertDialog.Builder(this);
                                                                                                                                                STATUS BAR
                                                                                                                                                La status bar (o barra di
builder.setTitle("Avviso");                                                     Alla risposta positiva programmata con set-                     stato) è la barra
builder.setMessage("Attenzione! Questo è un avviso!");                          PositiveButton(), abbiamo aggiunto ora una risposta             posizionata nella parte alta
builder.setCancelable(true);                                                    negativa, con setNegativeButton(). Il metodo è simi-            dello schermo, quella che
AlertDialog alert = builder.create();                                           le al precedente: anche in questo caso dobbiamo                 contiene l’orologio, per
                                                                                fornire un listener che intercetti la pressione sul bot-        intenderci. La barra di stato
                                                                                                                                                di Android viene utilizzata,
Come è possibile osservare, la finestra di dialogo                              tone e gestisca di conseguenza l’evento.                        tra le altre cose, anche per
viene prodotta servendosi di uno speciale ogget-                                E se volessimo fornire la facoltà di scegliere fra più di       trasmettere delle notifiche
to AlertDialog.Builder. A questo oggetto builder                                due opzioni? Anche questo è possibile:                          all’utente. Ad esempio
si deve dire quali sono le caratteristiche                                                                                                      quando arriva un SMS la
dell’AlertDialog desiderato, e per farlo sono a                                 final String[] options = { "Caffè", "Gelato", "Tè",
                                                                                                                                                barra si attiva e mostra
                                                                                                                                                un’icona che segnala
disposizione numerosi metodi. In questo caso                                                                              "Birra", "Ragù" };
                                                                                                                                                l’evento all’utente. L’utente
abbiamo specificato il titolo, con setTitle(), ed il                            AlertDialog.Builder builder = new                               può poi “srotolare” la barra
messaggio, con setMessage(). Con il comando                                                                        AlertDialog.Builder(this);   ed esaminare i dettagli
setCancelable(true) abbiamo fatto in modo che                                   builder.setTitle("Scelta multipla");                            della notifica ricevuta.
l’avviso possa essere chiuso con il tasto “back”                                builder.setItems(options, new
                                                                                                                                                Anche le applicazioni
                                                                                                                                                custom possono segnalare
del telefono. Il metodo create(), a questo punto, è                             ...
                                                                                                                                                delle notifiche all’utente
stato invocato per produrre la finestra di dialogo.                                                                                             utilizzando questo sistema.
Una finestra di dialogo così realizzata, adesso,                                In questo caso non si sono usati né setMessage()                Più che le attività, ad ogni
potrebbe essere restituita dal metodo                                           né     i     metodi      setPositiveButton()     e              modo, in genere sono i
onCreateDialog(), producendo un risultato come                                  setNegativeButton(). Si è invece fatto ricorso al               servizi a farlo. Per
                                                                                                                                                approfondire:
quello in Fig.4. Facciamo ora il caso di voler pro-                             metodo setItems(). Questo metodo vuole come
durre un avviso identico al precedente, ma che,                                 argomento un array di stringhe. Ciascuna delle                  http://developer.android.c
invece di costringere l’utente ad usare il tasto                                stringhe fornite sarà un’opzione di scelta. Ancora              om/guide/topics/ui/notifie
“back” del dispositivo, metta a disposizione esso                               una volta, il secondo argomento da fornire è il                 rs/notifications.html
stesso un bottone “chiudi”. Ecco come fare:                                     gestore di eventi. Quando una delle opzioni sarà
                                                                                selezionata dall’utente, il metodo onClick() del
AlertDialog.Builder builder = new                                               gestore verrà automaticamente richiamato.
                                                   AlertDialog.Builder(this);   L’argomento which, in questo caso, riporterà l’in-
builder.setTitle("Avviso");                                                     dice dell’opzione selezionata. L’elenco di opzioni
builder.setMessage("Attenzione! Questo è un avviso!");
builder.setCancelable(false);
builder.setPositiveButton("Chiudi", new
...


Con setCancelable(false) abbiamo disabilitato il
tasto fisico del dispositivo, mentre con
setPositiveButton() abbiamo aggiunto il bottone
“chiudi”. Al metodo abbiamo dovuto anche fornire
un oggetto di tipo android.content.DialogInterface.
OnClickListener. Si tratta, come è facile intuire, di un
gestore di eventi richiamato alla pressione del tasto                           Fig. 4: Un avviso che può essere chiuso con il tasto
“chiudi”. Con una chiamata a dismissDialog() faccia-                            “back” del telefono


h t t p : / / w w w. i o p r o g r a m m o . i t
      44                                                                                                                                          2010/ g r am m
                                                                                                                                           MaggioAnd roi d pr o 65Gin g
                                               Android: corso di programmazione
                                  MOBILE � corso di programmazione
                                    Android:                               Android programming




                                    Fig. 5: Un avviso che può essere chiuso attraverso il           Fig. 6: Una richiesta di conferma con due bottoni
                                    suo stesso bottone “chiudi”


                                                                                                    final String[] options = { "Caffè", "Gelato", "Tè",
                                    può essere anche popolato con dei bottoni radio o                                                               "Birra", "Ragù" };
                                    con delle caselle di tipo checkbox. Nel primo caso              final boolean[] selections = { true, false, false, false,
Fig. 7: Un AlertDialog
con numerose opzioni                si deve utilizzare, al posto di setItems(), il metodo                                                                           false };
                                    setSingleChoiceItems(). Questo metodo vuole tre                 AlertDialog.Builder builder = new lertDialog.Builder(this);
                                    parametri: l’array di stringhe con le opzioni, l’in-               ...
                                    dice dell’opzione inizialmente selezionata e, infi-
                                    ne, il solito gestore di eventi. Ad esempio:                    Nel CD-Rom troverete numerosi esempi completi
                                                                                                    relativi alle finestre AlertDialog, che riassumono e
                                    final String[] options = { "Caffè", "Gelato", "Tè",             dimostrano quanto spiegato in questo paragrafo.
                                                                              "Birra", "Ragù" };
                                    AlertDialog.Builder builder = new
                                                                       AlertDialog.Builder(this);
                                    builder.setTitle("Scelta multipla");                            PROGRESSDIALOG
                                    builder.setSingleChoiceItems(options, 2, new                    Può capitare che sia necessario svolgere delle opera-
                                                            DialogInterface.OnClickListener() {     zioni non istantanee, che possono cioè durare qual-
                                        ...                                                         che secondo o anche di più. Quando avviene ciò, si
                                                                                                    deve far capire all’utente che c’è un’operazione in
Fig. 8: Un AlertDialog
con le opzioni rese                 In questo caso si è tornati ad aggiungere i tasti di            corso, e che bisogna attendere fiduciosi. Se non lo si
come bottoni radio                  conferma e di cancellazione. Ciò ha senso: l’utente             fa, l’utente potrebbe pensare che l’applicazione non
                                    seleziona nell’elenco l’opzione desiderata e quindi             gli sta rispondendo perché è lenta o, peggio ancora,
                                    conferma la sua scelta con l’apposito bottone. Visto            perché si è bloccata.
                                    che i listener, in questo caso, crescono di numero,             Questo, naturalmente, è male. Per fortuna in casi
                                    si deve fare attenzione a mettere in atto una corret-           come questo ci si può servire di una
                                    ta politica di gestione degli eventi. La scelta multi-          android.app.ProgressDialog. Si tratta di una finestra
                                    pla, infine, è possibile usando dei checkbox. Il                di dialogo concepita appositamente per mettere in
                                    metodo        utile,     in     questo       caso,     è        attesa l’utente. Lo scopo è duplice: da una parte
                                    setMultiChoiceItems(). Il metodo chiede tre para-               blocca l’attività, in modo che non si possa far altro
                                    metri. Il primo è la lista delle opzioni, così come la          che attendere, mentre allo stesso tempo comunica
                                    abbiamo già conosciuta nei due casi precedenti. Il              all’utente che l’applicazione sta lavorando alacre-
                                    secondo argomento è un array di booleani, i cui                 mente e che tutto procede come previsto.
                                    elementi corrispondono a ciascuna delle opzioni                 Opzionalmente si può mostrare anche il progresso
                                    possibili, indicando se l’opzione corrispondente è              dell’operazione. Ad esempio durante un download è
Fig. 9: Un AlertDialog
con le opzioni rese                 inizialmente selezionata o meno. Il terzo argomen-              possibile far vedere la percentuale di completamen-
come checkbox, per                  to è il gestore degli eventi. Questa volta l’interfaccia        to raggiunta. Quando la barra di avanzamento non
consentire una scelta               è DialogInterface.OnMultiChoiceClickListener. Il                viene mostrata si dice che la ProgressDialog è inde-
multipla                            metodo onClick() di questa interfaccia si differen-             terminata. La maniera più facile per creare una
                                    zia da quello di OnClickListener perché prevede un              ProgressDialog indeterminata è attraverso il suo
                                    terzo parametro. Si tratta di un booleano chiamato              metodo statico:
                                    isChecked, che serve a indicare se l’opzione toccata
                                    dall’utente è stata selezionata o meno. Ecco un                 public static ProgressDialog show(Context context,
                                    esempio di quanto detto:                                        CharSequence title, CharSequence message)



   G 66 / Maggio 2010
                                                                                                                                 h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                                      45
                                            Android: corso di programmazione
                             Android programming                                  � MOBILE
                                                         Android: corso di programmazione


Il metodo crea e restituisce una finestra di attesa          accetta un intero compreso tra 0 ed il valore massi-
indeterminata, quindi senza barra di progresso.              mo previsto. Ad esempio:
Richiede come parametri il contesto dell’applicazio-
ne (tipicamente l’attività stessa che sta creando la         progress.setSecondaryProgress(30);
finestra), il titolo da assegnare alla finestra ed il mes-
saggio da mostrare al suo interno. Le ProgressDialog
con barra di avanzamento sono leggermente più
complesse. L’oggetto, in questo caso, va costruito           FINESTRE
manualmente richiamando il costruttore:                      DI DIALOGO CUSTOM
                                                             Se AlertDialog e ProgressDialog non dovessero anda-
ProgressDialog progress = new ProgressDialog(this);          re bene per una vostra specifica esigenza, potete
                                                             sempre procedere alla costruzione e all’utilizzo di
Bisogna poi specificare che la barra che si sta crean-       una finestra di dialog custom, cioè i cui contenuti
do non è indeterminata:                                      sono stabiliti in tutto e per tutto da voi. Vediamo
                                                             insieme come procedere. Ancora una volta, la
progress.setIndeterminate(false);                            miglior cosa da farsi è realizzare un layout XML.                Fig. 10: Una ProgressDialog
                                                             Realizziamo insieme il seguente:                                 indeterminata (cioè senza
                                                                                                                              barra di avanzamento)
Adesso si deve indicare di usare la barra orizzontale:
                                                             <LinearLayout xmlns:android="http://schemas
progress.setProgressStyle(ProgressDialog.STYLE_HORIZ                                      .android.com/apk/res/android"
                                                   ONTAL);             ...


L’avanzamento raggiunto deve essere espresso                 Chiamate il file custom_dialog.xml e disponetelo
mediante un valore che va da 0 a 100. Se, per qual-          nella cartella res/layout del vostro progetto Android.
che motivo, questo range non fosse adatto ad una             Questo layout mette insieme un’immagine ed un
vostra esigenza, potete cambiarne il limite superio-         testo. Né l’immagine né il testo, però, sono specifi-
re, invocando il metodo setMax(). Ad esempio:                cati a livello di XML: realizzeremo ora una classe               Fig. 11: Una ProgressDialog
                                                             estensione di Dialog che permetterà di impostare                 con barra di avanzamento
                                                                                                                              secondaria
progress.setMax(1000);                                       l’uno e l’altra. Chiamiamola Custom Dialog:

Così facendo, il valore di progresso raggiunto potrà         import android.app.Dialog;
essere espresso nel range che va da 0 a 1000.                import android.content.Context;
A questo punto, la finestra di dialogo può essere            import android.os.Bundle;
restituita e visualizzata. Su un thread parallelo biso-      import android.widget.ImageView;
gna intanto iniziare a svolgere l’operazione di cui          import android.widget.TextView;
l’utente attende la conclusione. Di tanto in tanto,          public class CustomDialog extends Dialog {...
mentre si svolge tale operazione, è necessario
aggiornare la barra di avanzamento della                     Come potete vedere, estendere Dialog non è poi
ProgressDialog, per informare l’utente circa il punto        tanto diverso da estendere Activity. All’atto di crea-
raggiunto. Per farlo è disponibile il metodo                 zione della finestra abbiamo provveduto affinché il
setProgress(), che accetta come parametro un valore          layout XML realizzato in precedenza venga caricato               Fig. 12: Una finestra di dialo-
                                                                                                                              go completamente custom
intero che rappresenta il livello di completamento           e mostrato all’interno della finestra. Abbiamo poi
raggiunto. Ad esempio:                                       predisposto i metodi setImage() e setMessage(), che
                                                             impostano l’immagine ed il testo visualizzati nel
                                                                                                                                        L’AUTORE
progress.setProgress(50);                                    layout. Ora possiamo utilizzare la classe
                                                             CustomDialog in un’attività. Basterà fare qualcosa              Carlo Pelliccia lavora presso
Il valore espresso deve essere compreso nel range di         del tipo:                                                       4IT (www.4it.it), dove si
default (da 0 a 100) o in quello esplicitamente modi-                                                                        occupa di analisi
ficato in precedenza chiamando setMax(). Per le              private static final int DIALOG_CUSTOM_ID = 1;                  e sviluppo software per
                                                                                                                             piattaforme Java. Nella sua
operazioni più complesse si può addirittura usare            @Override
                                                                                                                             carriera di technical writer ha
una barra di progresso secondaria. Facciamo il caso          protected Dialog onCreateDialog(int id) {...}                   pubblicato cinque manuali ed
di un’applicazione che scarica dei file da Internet. Ad      @Override                                                       oltre centocinquanta articoli,
un certo punto deve scaricare dieci file. In questo          protected void onPrepareDialog(int id, Dialog dialog) {         molti dei quali proprio tra le
caso si può usare la barra di avanzamento principa-          ...                                                             pagine di ioProgrammo. Il
                                                                                                                             suo sito, che ospita anche
le per far vedere quanti file sono stati già scaricati, e
                                                                                                                             diversi progetti Java Open
la barra secondaria per mostrare il progresso rag-           Nel CD-Rom è disponibile l’esempio completo.                    Source, è disponibile
giunto dal singolo file che di volta in volta viene sca-                                                                     all’indirizzo
ricato. Il metodo utile è setSecondaryProgress(), che                                                   Carlo Pelliccia      www.sauronsoftware.it


h t t p : / / w w w. i o p r o g r a m m o . i t
    46                                                                                                                        2010/ 67 in
                                                                                                                       Maggio And roi d pr o g r am mGg
                                        MOBILE tabelle eListe, tabelle e gallerie di immagini programming
                                          Liste, �       gallerie di immagini           Android




INFO E FOTO: COSÌ
LE PRESENTI MEGLIO!
NONO APPUNTAMENTO. CI OCCUPEREMO DEI WIDGET IN GRADO DI LEGGERE
LE INFORMAZIONI DA ORGANIZZARE E MOSTRARE ALL’UTENTE. SCOPRIREMO
I COMPONENTI UTILIZZATI PER REALIZZARE LISTE, TABELLE E GALLERIE DI IMMAGINI




                                          T
                                                  utti i layout dimostrati negli esempi dei
                                                  mesi precedenti sono dei layout “fissi”. I
                                                  widget di un layout fisso sono sempre gli
                                          stessi e non cambiano ruolo nel corso del tempo:
                                          ogni volta che si avvia l’attività, i componenti
                                          mostrati sono sempre gli stessi e la schermata, di
                                          conseguenza, appare sempre uguale. Ripensate,
                                          ad esempio, a quando abbiamo dimostrato l’uso
    ❑ CD ❑ WEB                            di etichette, bottoni e caselle di testo realizzando
    corso_android_9.rar
                                          un form per l’immissione delle generalità ana-
                 cdrom.ioprogrammo.it
                                          grafiche (nome, cognome, sesso) dell’utente. È
                                          stato fatto nei numeri 146 e 147 della rivista.
                                          Pensate ad un’applicazione come la rubrica del
                                          telefono, oppure la galleria delle immagini. Si tratta    Fig. 1: La galleria delle immagini di Android è il clas-
                                          di attività il cui contenuto cambia di continuo. Se       sico esempio di applicazione il cui layout non è fisso,
                                                                                                    in quanto il numero dei widget presenti dipende da
                                          aggiungo un contatto o se scatto una nuova foto, ad       una fonte esterna
                                          esempio, ecco che nelle corrispondenti applicazio-
                                          ni apparirà un nuovo elemento.
                                          In questo genere di applicazioni, quindi, il numero
                                          ed il tipo dei widget presenti non è sempre lo stes-      dati (nel caso specifico, le immagini lette dalla
                                          so, ma dipende da una fonte di informazioni ester-        memoria) con lo strato dell’interfaccia utente (con-
                                          na. La galleria delle immagini, ad esempio, costrui-      tenitori e widget). Ciò, secondo tutti i più moderni
                                          sce e mostra tanti widget quanti sono quelli neces-       paradigmi della programmazione orientata agli
                                          sari per mostrare i file immagine presenti in             oggetti, è male. Non vorrete mica cedere al lato
                                          memoria. Con le nozioni acquisite finora siamo in         oscuro della forza, vero? Per nostra fortuna la libre-
                                          grado di costruire un adattatore di questo tipo.          ria di Android mette a disposizione una serie di
                                          Sarebbe sufficiente, all’interno di un’attività, scri-    strumenti che permettono di ottenere layout dina-
                                          vere un ciclo for o qualcosa di analogo che, per ogni     mici, in maniera assolutamente semplice, corretta
                                          elemento riscontrato nella fonte dei dati, vada ad        e pulita. Basta solo imparare a utilizzarli.
                                          aggiungere al contenitore corrente tutti i widget
                                          necessari per mostrarlo. Qualcosa come:
              REQUISITI
                                          @Override                                                 ADAPTERVIEW
 Conoscenze richieste
    Basi di Java                          public void onCreate(Bundle savedInstanceState) { ... }   E ADAPTER
                                                                                                    Il primo componente che andiamo a svelare è la
 Software                                 Una tecnica come questa funziona (bisognerebbe            classe astratta android.widget.AdapterView. La clas-
     Java SDK (JDK) 5+,
     Eclipse 3.3+                         usare qualche altra accortezza in più, in verità, ma      se estende ViewGroup e, pertanto, è un contenitore
                                          l’esempio serve giusto per rendere il concetto), ma       di altri widget. I suoi widget, però, non devono esse-
                                          nell’ottica della programmazione Android non è il         re aggiunti facendo uso esplicito dei metodi
                                          massimo. I layout XML, ad esempio, in un caso             addView() messi a disposizione dal contenitore. Le
 Impegno
                                          come questo non risultano facilmente applicabili.         istanze di AdapterView, infatti, sono in grado di
¥                                         Se la schermata va costruita iterativamente, infatti,     determinare da sole i loro contenuti, partendo da
Tempo di realizzazione
                                          c’è poca speranza di farlo senza il supporto della        una sorgente esterna di informazioni che gli sugge-
                                          logica Java. La pratica, inoltre, tende a mischiare i     risce quanti e quali sono gli elementi da mostrare.

                                                                                                                               h t t p : / / w w w. i o p r o g r a m m o . i t
     G 64 / Giugno 2010
A n d ro id p r o g r a m m ing                                                                                                                                    47
                                           Liste,
                            Android programming tabelle e gallerie di immagini di immagini
                                                        Liste, tabelle e gallerie  � MOBILE


Questa sorgente deve una implementazione dell’in-                           derlo, e può farlo in XML. Si può usare un layout
terfaccia android.widget.Adapter. Sono le istanze di                        XML per dichiarare da quali widget sarà composto
Adapter a determinare gli elementi che devono esse-                         ciascun elemento della lista. L’unico vincolo è che
re mostrati, facendo da tramite tra l’attività e la fonte                   questo layout deve necessariamente contenere un
esterna. AdapterView risponderà ai comandi di                               widget TextView. Soddisfatto questo requisito, è suf-
Adapter, mostrando esattamente quanto richiesto.                            ficiente notificare all’ArrayAdapter quale è il layout
Per realizzare delle schermate di questo tipo potete                        XML e quale, al suo interno, è l’id del TextView da
estendere da voi AdapterView e implementare come                            utilizzare. Lo si può fare nel costruttore dell’adapter.
meglio credete l’interfaccia Adapter, ma in verità                          Partendo da un layout listitem.xml così definito:
molto raramente vi accadrà di farlo. Android dispo-
ne già di ottime implementazioni pronte all’uso, in                         <?xml version="1.0" encoding="utf-8"?>
grado di coprire la stragrande maggioranza delle esi-                       <LinearLayout xmlns:android="http://schemas.
genze di programmazione. Nei prossimi paragrafi                                                       android.com/apk/res/android"
conosceremo le implementazioni di Adapter, per                                  android:layout_width="wrap_content"
poi applicarle insieme alle estensioni di                                       android:layout_height="wrap_content">
AdapterView disponibili nella libreria di base.                                 <TextView android:layout_width="wrap_content"
                                                                                    android:layout_height="wrap_content"
                                                                                    android:padding="5pt"                                          NOTA
                                                                                    android:textSize="10pt"
ARRAYADAPTER                                                                        android:id="@+id/listItemTextView" />
                                                                                                                                        GENERICS
Un adattatore semplice e veloce da utilizzare è                             </LinearLayout>                                             I generics sono una
costituito dalla classe android.widget.Array-                                                                                           caratteristica di Java
Adapter. Come il nome suggerisce, si tratta di un                           Si può fare:                                                introdotta a partire dalla
adattatore che si comporta un po’ come un array, in                                                                                     versione 5 della
                                                                                                                                        piattaforma. L’utilizzo più
quanto dispone di metodi utili per aggiungere,                              ArrayAdapter<String> arrayAdapter = new
                                                                                                                                        comune che se ne fa è per
verificare e rimuovere gli elementi al suo interno.                                    ArrayAdapter<String>(this, R.layout.listitem,    qualificare il tipo di dato
La classe fa uso dei generics di Java per gestire                                                             R.id.listItemTextView);   contenuto in un insieme o
meglio il tipo degli elementi al suo interno, proprio                                                                                   in una lista, evitando così la
come fanno anche java.util.ArrayList o                                      Ora non resta che aggiungere gli elementi all’adap-         necessità di casting
                                                                                                                                        continuo. Prima di Java 5,
java.util.Vector. Quando si crea un oggetto di tipo                         ter. Il metodo suo add() è quel che ci vuole:               infatti, un ArrayList di
ArrayAdapter, quindi, bisogna specificare il tipo                                                                                       stringhe si sarebbe dovuto
degli elementi che conterrà. Ad esempio:                                    arrayAdapter.add("Carlo");                                  gestire alla seguente
                                                                            arrayAdapter.add("Claudia");                                maniera:
ArrayAdapter<String> arrayAdapter = new                                     arrayAdapter.add("Silvia");
                                               ArrayAdapter<String>(...);   arrayAdapter.add("Alessandro");                             ArrayList list = new
                                                                                                                                                       ArrayList();
In questo esempio gli elementi trattati dall’adattato-                      Ovviamente inserire gli elementi della lista in que-        list.add("stringa");
re sono delle stringhe. Al posto delle stringhe, se                         sta maniera non è il massimo. Gli adattatori, infat-        String str = (String)
necessario, potete utilizzare qualsiasi classe vi faccia                    ti, servono per assorbire elementi dall’esterno, ad                           list.get(i);
comodo per il caso specifico. Fate però attenzione al                       esempio dal file system o dal database del sistema.
fatto che gli ArrayAdapter sono stati concepiti per                         Di questo aspetto, naturalmente, ci occuperemo              Con i generics, invece, è
                                                                                                                                        possibile fare:
lavorare con il testo. Il loro scopo è iniettare dei wid-                   nei mesi a venire. Per ora continuiamo a concen-
get TextView all’interno dell’AdapterView che li uti-                       trarci sulla classe ArrayAdapter. Gli elementi al suo       ArrayList<String> list =
lizza. I TextView, vi ricordo, sono dei widget testuali,                    interno possono essere recuperati con il metodo               newArrayList<String>();
utili per mostrare una stringa a schermo. Nel caso di                       getItem(int position), rimossi uno ad uno con               list.add("stringa");
un ArrayAdapter di stringhe, quindi, gli elementi                           remove(T item), ripuliti completamente con clear()          String str = list.get(i);
aggiunti nell’adattatore saranno mostrati diretta-                          o conteggiati con getCount(). Da questo punto di
mente con delle etichette di testo. Se gli elementi                         vista, gestire un ArrayAdapter è proprio come gesti-        Per approfondire:
gestiti, invece, non sono delle stringhe ma degli                           re un comune java.util.ArrayList, fatta salva qual-         http://tinyurl.com/
oggetti qualsiasi, nei TextView generati sarà intro-                        che differenza nel nome dei metodi.                         jgenerics
dotta la rappresentazione testuale di ciascun ele-
mento, ottenuta richiamando il metodo toString()
dell’oggetto corrispondente. Oltre alla classe degli
elementi da gestire, ArrayAdapter vuole sapere                              IMPLEMENTARE
anche come rappresentarli. Come accennato,                                  IL PROPRIO ADAPTER
ArrayAdapter userà una TextView per ciascun ele-                            Come abbiamo appena appreso, un ArrayAdapter è
mento previsto. Come questa TextView è fatta e in                           proprio quello che ci vuole quando i dati gestiti
che contesto è inserita spetta allo sviluppatore deci-                      sono una lista testuale o, comunque, rappresenta-

h t t p : / / w w w. i o p r o g r a m m o . i t
    48                                                                                                                           Giugno 2010 / o g r am m in g
                                                                                                                                        And roi d pr 65 G
                                  MOBILE tabelle eListe, tabelle e gallerie di immagini programming
                                    Liste, �       gallerie di immagini           Android


                                    bile sotto forma di testo. In alcuni casi, però, questo    <ListView
                                    non è vero. È il caso, per tornare su un esempio già             android:layout_width="fill_parent"
                                    citato, della galleria delle immagini. In questa                 android:layout_height="wrap_content"
                                    situazione, infatti, l’adapter non deve occuparsi di             android:id="@+id/miaLista" />
                                    testo e non deve generare widget di tipo TextView.
                                    Nel caso della galleria delle immagini gli oggetti da      Non dimenticatevi mai di assegnare un id ai vostri
                                    produrre saranno piuttosto dei componenti                  oggetti ListView dichiarati in un layout XML, in
                                    ImageView. Bisogna allora realizzarsi un adapter           modo da poterli poi recuperare e sfruttare nel codi-
                                    idoneo. La maniera più veloce di creare un adatta-         ce Java dell’attività con un’istruzione del tipo:
                                    tore custom consiste nell’estendere la classe astrat-
                                    ta android.widget.BaseAdapter. I metodi da imple-          ListView listView = (ListView)
                                    mentare sono:                                                                             findViewById(R.id.miaLista);


                                    • public int getCount() Questo metodo restituisce          Una volta creato l’oggetto, bisogna assegnargli un
                                      il numero di elementi presenti nell’adattatore.          Adapter affinché sia possibile caricare dei dati al
                                                                                               suo interno. Il metodo utile è setAdapter():
                                    • public Object getItem(int position) Resttituisce
                                      l’elemento alla posizione indicata.                      listView.setAdapter(mioAdapter);


Fig. 2: Un esempio di               • public long getItemId(int position) Restituisce          Che adattatore utilizzare? Un ArrayAdapter o un
ListView con                          un id per l’elemento alla posizione indicata.            adattatore custom ottenuto per estensione di
ArrayAdapter                                                                                   BaseAdapter, come mostrato in precedenza,
                                    • public View getView(int position, View                   andranno benissimo.
                                      convertView, ViewGroup parent) Questo è il               Gli eventi di tocco e tocco lungo su un oggetto della
                                      metodo più importante del lotto. Deve restituire         lista possono essere gestiti applicando degli appo-
                                      il widget che rappresenterà l’elemento sullo             siti listener all’oggetto ListView. Il tocco semplice
                                      schermo. L’indice dell’elemento da rappresenta-          può essere intercettato usando il metodo
            NOTA                      re è dato dal parametro position. Il parametro           setOnItemClickListener() e l’interfaccia android.
                                      convertView costituisce il widget generato dall’a-       widget.AdapterView.OnItemClickListener:
    CURSORADAPTER                     dapter ad una sua precedente chiamata. Se pos-
Un altro Adapter di Android           sibile, infatti, l’adattatore deve cercare di ricicla-   listView.setOnItemClickListener(new
             molto utilizzato è       re i widget, per risparmiare memoria. Il parame-                                               OnItemClickListener() {
android.widget.CursorAdap
                                      tro parent, infine, è il contenitore che dovrà ospi-           @Override
   ter. Non è stato illustrato
  nell’articolo in quanto per         tare il widget generato o riciclato.                           public void onItemClick(AdapterView<?>
     la sua comprensione è                                                                                 adapterView, View view, int position, long id) {
necessario conoscere cosa           Ecco un esempio di implementazione che permet-                       // ...
    sia e come si utilizza un       te di gestire una lista di immagini (fornite sotto               }
        Cursor. Un cursore è
                                    forma di oggetti android.graphics.drawable.                });
  l’oggetto che permette di
   scorrere i risultati di una      Drawable):
  query svolta al sistema di                                                                   Gli argomenti forniti al metodo onItemClick() sono:
         database interno ad        import android.content.Context;
         Android, e dunque il       ...                                                        • AdapterView<?> adapterView
         CursorAdapter è un
                                    public class ImageAdapter extends BaseAdapter {... }         L’AdapterView che ha subito l’evento.
        adattatore ideale per
     impaginare e mostrare
          all’utente i dati che                                                                • View view
           provengono da un                                                                      Il widget all’interno dell’AdapterView che ha
  database. Ne riparleremo
                     in futuro.
                                    LA CLASSE LISTVIEW                                           subito l’evento.
                                    La classe android.widget.ListView permette di rea-
                                    lizzare delle liste di elementi con scrolling verticale.   • int position
                                    Le istanze di ListView, come quelle di ogni altro            La    posizione     del   widget     all’interno
                                    widget, possono essere costruite indifferentemente           dell’AdapterView, come indice da zero in su.
                                    con codice Java o XML. Nel primo caso, dall’inter-
                                    no di un’attività, si farà qualcosa come:                  • long id
                                                                                                 L’id della riga dell’AdapterView che ha subito l’e-
                                    ListView listView = new ListView(this);                      vento.

                                    Nel caso del codice XML, invece, sarà necessario           Il tocco lungo richiede il metodo setOnItem
                                    fare qualcosa del tipo:                                    LongClickListener() e l’interfaccia android.wid-


   G 66 / Giugno 2010
                                                                                                                            h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                                 49
                                           Liste,
                            Android programming tabelle e gallerie di immagini di immagini
                                                        Liste, tabelle e gallerie  � MOBILE


get.AdapterView.OnItemLongClickListener. Il meto-                                per la dimensione.
do da implementare è onItemLongClick(). Gli argo-                              • setGravity(int) Imposta la costante di gravità per
menti sono gli stessi di onItemClick():                                          l’allineamento dei widget. Il valore di default è
                                                                                 Gravity.LEFT. In XML l’attributo corrispondente è
listView.setOnItemLongClickListener(new                                          android:gravity.
                                                   OnItemLongClickListener()
{                                                                              • setStretchMode(int) Quando la tabella è più pic-
      @Override                                                                  cola del contenitore al quale si deve adattare, que-
      public boolean onItemLongClick(AdapterView<?>                              sto metodo permette di specificare la politica da                     NOTA
                  adapterView, View view, int position, long id)                 adottare per distribuire lo spazio in più fra le
{                                                                                colonne. I valori possibili sono GridView.                 LISTACTIVITY
            // ...                                                               NO_STRETCH (nessun ridimensionamento auto-                 Quando un’attività è
      }                                                                          matico delle colonne rispetto alle loro dimensioni         costituita esclusivamente
});                                                                              previste), GridView.STRETCH_SPACING (distri-               da una lista, Android mette
                                                                                                                                            a disposizione una pratica
                                                                                 buisce lo spazio aggiuntivo come spaziatura tra
                                                                                                                                            e proficua scorciatoia:
Nel CD-Rom allegato alla rivista trovate una demo                                una colonna e la successiva), GridView.STRETCH_            invece di creare una classe
riassuntiva che mette insieme un contenitore                                     SPACING_UNIFORM (come il precedente, ma                    Activity all’interno della
ListView con un adattatore ArrayAdapter.                                         aggiunge spazio anche prima della prima colonna            quale si deve definire un
                                                                                 e dopo l’ultima) e GridView.STRETCH_ COL-                  layout basato su un
                                                                                                                                            componente ListView ed il
                                                                                 UMN_WIDTH (assegna lo spazio aggiuntivo alle
                                                                                                                                            relativo Adapter, si può
                                                                                 singole colonne). In XML l’attributo corrispon-            estendere direttamente la
LA CLASSE GRIDVIEW                                                               dente è android:stretchMode, ed i valori possibili         classe
La classe android.widget.GridView è il componente                                sono none, spacingWidth, spacingWidth Uniform              android.app.ListActivity.
per costruire una tabella. Quando si crea l’oggetto è                            e columnWidth.                                             Così facendo non c’è
                                                                                                                                            bisogno di definire il layout,
importante specificare quante colonne si vogliono
                                                                                                                                            e l’adattatore può essere
usare al suo interno. In Java si fa così:                                      L’adapter può essere impostato chiamando il meto-            impostato direttamente
                                                                               do setAdapter() su un oggetto GridView, proprio              sull’attività chiamando il
GridView gridView = new GridView(this);                                        come nel caso di ListView. L’adattatore viene inter-         suo metodo
gridView.setNumColumns(3);                                                     rogato per estrarre gli elementi che faranno parte           setListAdapter().
                                                                               della griglia. Facciamo il caso che la griglia abbia tre
In XML, invece:                                                                colonne. Il primo elemento fornito dall’adattatore
                                                                               andrà alla posizione in riga 1 e colonna 1 della gri-
<GridView android:layout_width="fill_parent"                                   glia; il secondo finirà a riga 1 e colonna 2, il terzo a
      android:layout_height="fill_parent"                                      riga 1 e colonna 3. Terminata la riga, il quarto ele-
      android:numColumns="3"                                                   mento dell’adattatore proseguirà a partire dalla riga
      android:id="@+id/miaGriglia" />                                          successiva. Quindi il quarto elemento sarà visualiz-
                                                                               zato a riga 2 e colonna 1, il quinto a riga 2 e colonna
Altri metodi ed attributi permettono di impostare                              2, e così via. La griglia, per farla più semplice, viene
ulteriori proprietà della griglia:                                             popolata da sinistra verso destra e dall’alto verso il
                                                                               basso. Anche in questo caso è possibile intercettare
• setColumnWidth(int) Imposta la larghezza delle                               eventi di tocco e tocco lungo sui singoli elementi
  colonne con un valore in pixel. L’attributo XML                              della griglia. Ancora una volta, i metodi utili sono
  corrispondente è android:columnWidth, che                                    setOnItemClickListener() e setOnItemLongClick-
  permette di specificare anche un’unità di misura                             Listener(), con le corrispettive interfacce
  differente dai pixel (ad esempio “10pt”).                                    AdapterView.OnItemClickListener e AdapterView.-
                                                                               OnItemLongClickListener. Nel CD-Rom troverete il
• setHorizontalSpacing(int) Imposta la distanza                                codice completo dell’esempio mostrato in Fig. 4.
  orizzontale tra un elemento e l’altro della griglia
  con un valore in pixel. L’attributo XML corrispon-
  dente è android:horizontalSpacing, che permet-
  te di specificare anche un’unità di misura diffe-                            SPINNER                                                     Fig. 3: GridView in azio-
                                                                                                                                           ne, con una matrice di
  rente dai pixel per la dimensione.                                           Uno spinner è un elenco a tendina dal quale è pos-          dodici immagini distri-
                                                                               sibile selezionare un elemento. In Android gli spin-        buite su tre colonne
• setVerticalSpacing(int) Imposta la distanza verti-                           ner sono delle estensioni di AdapterView, e quindi
  cale tra un elemento e l’altro della griglia con un                          rientrano nella panoramica odierna. Utilizzarli è
  valore in pixel. L’attributo XML corrispondente è                            davvero molto semplice, anche perché sono dei
  android:verticalSpacing, che permette di specifi-                            componenti più basilari rispetto ai ListView o i
  care anche un’unità di misura differente dai pixel                           GridView esaminati nei paragrafi precedenti. Il


h t t p : / / w w w. i o p r o g r a m m o . i t
    50                                                                                                                                     2010 / 67G
                                                                                                                                    Giugno And roi d pr o g r am m in g
                                                    Liste, tabelle e gallerie
                                    MOBILE tabelle e gallerie di immagini di immagini programming
                                      Liste, �                                  Android


                                      codice Java è il seguente:                                    View) Questo metodo viene richiamato quando
                                                                                                    la selezione precedente viene annullata, e quindi
                                      Spinner spinner = new Spinner(this);                          nessuna voce è selezionata. L’argomento
                                                                                                    adapterView rappresenta l’oggetto che ha subito
                                      In XML diventa:                                               l’evento, che nel caso specifico sarà quindi uno
                                                                                                    Spinner.
                                      <Spinner android:layout_width="fill_parent"
                                           android:layout_height="wrap_content"                   Ecco un esempio in grado di funzionare con uno
                                           android:id="@+id/mioSpinner"                           spinner i cui elementi sono stringhe:
                                      />
                                                                                                  spinner.setOnItemSelectedListener(new
                                      Opzionalmente, con il metodo setPrompt() o con                                               OnItemSelectedListener()
                                      l’attributo android:prompt, è possibile dare un               {...
                                      titolo alla lista di scelte che viene mostrata all’at-
                                      tivazione dello spinner. Per esempio:

                                      spinner.setPrompt("Seleziona l’elemento che                 IL COMPONENTE GALLERY
                                                                                  preferisci");   Chiudiamo la panoramica sugli AdapterView
                                                                                                  parlando del componente android.widget.
                                      I dati mostrati nella lista saranno, naturalmente,          Gallery. Come il nome lascia facilmente indovi-
Fig. 5: Esempio                       forniti da un adattatore che potete implementa-             nare, si tratta di un widget particolarmente adat-
di Spinner con elementi               re come meglio credete, per poi impostarlo con              to per la costruzione di gallerie di immagini.
testuali                              setAdapter():                                               L’oggetto Gallery, ad ogni modo, può gestire
                                                                                                  qualsiasi View al suo interno, e non solo quelle di
                                      spinner.setAdapter(mioAdapter);                             tipo ImageView. Il risultato prodotto è quello di
                                                                                                  una galleria sfogliabile, dove i dati inseriti all’in-
                                      In molti casi gli spinner vengono utilizzati con            terno del contenitore possono essere spostati
                                      elementi testuali, e quindi in accoppiata con un            verso destra o verso sinistra con il tocco del dito,
                                      ArrayAdapter.                                               per visualizzare l’elemento successivo o prece-
                                      Tuttavia non esistono vincoli in merito: se nella           dente. L’impiego di Gallery ricalca il modello
                                      vostra applicazione ha senso, potete utilizzare un          ripetuto più volte nei paragrafi precedenti. Si può
                                      qualsiasi altro adapter, per mostrare widget com-           cioè usare il codice Java:
            L’AUTORE                  plessi, magari con immagini, come elementi
                                      della lista di selezione. Quale sia l’elemento sele-        Gallery gallery = new Gallery(this);
 Carlo Pelliccia lavora presso        zionato è sempre possibile saperlo chiamando il
     4IT (www.4it.it), dove si        metodo getSelectedItem(). Lo vediamo in questo              Oppure, se preferite, potete usare la formulazione
              occupa di analisi       esempio:                                                    XML:
       e sviluppo software per
  piattaforme Java. Nella sua
carriera di technical writer ha       String voceSelezionata = (String)                           <Gallery
pubblicato cinque manuali ed                                       spinner.getSelectedItem();
 oltre centocinquanta articoli,                                                                      android:layout_width="fill_parent"
  molti dei quali proprio tra le      Su uno spinner non si possono usare                            android:layout_height="fill_parent"
    pagine di ioProgrammo. Il
                                      OnItemClickListener o OnItemLongClickListener,                 android:id="@+id/miaGalleria" />
    suo sito, che ospita anche
    diversi progetti Java Open        come nei due componenti studiati in precedenza.
          Source, è disponibile       Per intercettare la selezione di un elemento è però         Siccome spesso i componenti Gallery sono adope-
                    all’indirizzo     possibile fare ricorso al metodo setOnItem                  rati per sfogliare una serie di immagini, come adat-
   www.sauronsoftware.it              SelectedListener() e alla corrispettiva interfaccia         tatore potete usare l’ImageAdapter sviluppato
                                      android.widget.AdapterView.OnItemSelected                   qualche paragrafo sopra come estensione di
                                      Listener. Due, in questo caso, sono i metodi da             BaseAdapter:
                                      implementare:
                                                                                                  gallery.setAdapter(new ImageAdapter(this, images));
                                      • onItemSelected(AdapterView<?> adapterView,
                                        View view, int position, long id) Questo metodo           I listener utilizzabili sono, ancora una volta,
                                        viene richiamato alla selezione di un elemento            OnItemClickListener e OnItemLongClickListener.
                                        della lista. Gli argomenti sono equivalenti a quel-       Un esempio completo e funzionante lo potete tro-
                                        li già conosciuti con i metodi onItemClick() di           vare nel CD-Rom allegato alla rivista.
                                        OnItemClickListener.
                                      • onNothingSelected(AdapterView<?> adapter                                                                   Carlo Pelliccia



   G 68 / Giugno 2010
                                                                                                                             h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                                  51
                                                    Android: l’utilizzo e stili
                         Android programming Android: l’utilizzo di temidi temi e stili
                               MOBILE




UN’APPLICAZIONE
CON STILE
IL DESIGN È UNO DEI FATTORI PIÙ IMPORTANTI IN AMBITO MOBILE. NON È SUFFICIENTE
CHE UN’APPLICAZIONE FUNZIONI: DEVE ANCHE ESSERE ELEGANTE E GRADEVOLE ALLA
VISTA. PER QUESTO OGGI SCOPRIREMO COME GESTIRE IL LOOK DELLE APPLICAZIONI




                                        P
                                                 er tutta la durata di questo corso, abbiamo       che il testo sia grassetto e corsivo (con la proprietà
                                                 più volte rimarcato come Android spicchi tra      textStyle), di colore giallo (textColor), grande 20
                                                 gli altri sistemi mobili per la modernità dei     punti (textSize), con un font a spaziatura fissa (type-
                                        suoi concetti e per la tipologia dei suoi strumenti,       face) e distanziato di 10 punti dai bordi del widget
                                        soprattutto per quel che riguarda il design delle          (padding). Tutte queste proprietà potrebbero essere
                                        interfacce utente. Realizzare una UI per Android,          espresse anche con del codice Java, ma natural-
                                        infatti, è un’operazione che ricorda più il design di      mente in XML è molto più semplice configurare
                                        una pagina Web che non la costruzione di un’ap-            lo stile di un widget. Utilizzando Eclipse, poi, lo è
                                        plicazione a finestre su un sistema desktop. Grazie        ancora di più, visto che si possono utilizzare le pro-
❑ CD ❑ WEB
android_10.rar                          al linguaggio di layout basato su XML, in Android          cedure guidate messe a disposizione dal plug-in per
                                        ogni widget dell’interfaccia può essere velocemen-         lo sviluppo Android.
                 cdrom.ioprogrammo.it
                                        te espresso e configurato. Tra le tante cose che
                                        Android permette, c’è anche la possibilità di inter-
                                        venire sull’aspetto di ciascun widget, modifican-
                                        done ad esempio il colore, i bordi, lo stile del testo,
                                        l’immagine di sfondo e così via. Oggi ci concen-
                                        treremo proprio su questo aspetto, introducendo i
                                        concetti di stile e tema.                                  Fig. 1: Un componente TextView personalizzato nelle sue
                                                                                                   proprietà di stile




                                        BISOGNA AVERE STILE!                                       Supponiamo ora di voler sviluppare un’applica-
                                        Nel gergo di Android (e non solo), uno stile è un          zione che faccia uso di diverse decine di compo-
                                        insieme di proprietà che possono essere applicate          nenti TextView come quello appena dimostrato.
                                        ad un widget per modificarne l’aspetto esteriore. Ci       A livello di XML, magari aiutandoci con un po’
                                        è già capitato di utilizzare delle proprietà di stile in   di copia-incolla, potremmo naturalmente definire
                                        alcuni dei codici studiati durante gli appuntamenti        tanti widget tutti uguali, semplicemente replicando
                                        precedenti. Per andare dritti al punto, prendiamo          su ognuno di essi le medesime proprietà di stile.
                                        in esempio il caso di un componente TextView così          Come soluzione funziona, però non è il massimo
             REQUISITI
                                        definito:                                                  della convenienza. Anzitutto ci sono un sacco di
                                                                                                   definizioni duplicate, e questo già di per sé non è un
Conoscenze richieste                    <TextView                                                  buon inizio. La cosa peggiore, però, è che diventa
    Basi di Java                           android:layout_width=”fill_parent”                      più difficile mantenere omogeneo lo stile di tutta
                                           android:layout_height=”wrap_content”                    l’applicazione. Facciamo ad esempio il caso che
Software
                                           android:text=”@string/message”                          il cliente che ci ha commissionato l’applicazione,
    Java SDK (JDK) 5+,
    Android SDK, Eclipse                   android:textStyle=”bold|italic”                         dopo averla vista, ci dice “mi sa che ho cambiato
    3.3+, ADT
                                           android:textColor=”#FFFF00”                             idea e che le scritte adesso le voglio verdi e un po’
                                           android:textSize=”20sp”                                 più grosse”. In questo caso dovremmo tornare a
Impegno
                                           android:typeface=”monospace”                            lavorare su tutti gli XML, ricercando ogni occorren-
                                           android:padding=”10dp” />                               za di TextView e andando a correggere le proprietà.
Tempo di realizzazione
                                                                                                   Poi bisognerebbe riverificare ciascuna schermata
                                        Questa etichetta di testo ricorre a diverse proprietà      per essere sicuri di non aver commesso errori.
                                        di stile. Nello specifico, si richiede esplicitamente      Insomma, in fin dei conti quel copia-incolla iniziale


    54
  52 / Luglio 2010                                                                                                                    And roi d pr o g am m in t
                                                                                                                              h ttp ://www.io p rog rra m m o .ig
                                                Android: l’utilizzo e stili
                                         Android: l’utilizzo di temidi temi e stili                    MOBILE
                                                                                                 Android programming


potrebbe costarci parecchia fatica in futuro.              Questo TextView, una volta caricato in un’attività,
Per questo motivo Android mette a disposizione             apparirà identico a quello dimostrato in apertura
uno speciale costrutto XML che permette di definire        di paragrafo. Adesso, però, è possibile realizzarne
gli stili come delle entità indipendenti, slegate cioè     a iosa senza dover fare copia-incolla degli attributi
dal widget o dai widget cui sono applicate. Gli stili      di stile: basterà applicare a tutti lo stile textViewSt-
possono essere definiti negli XML di tipo resources,       yle01, e tutti i testi appariranno gialli e in grassetto.
come già siamo abituati a fare con le stringhe. La         La richiesta del cliente di cambiare le dimensioni
cartella di progetto da utilizzare, quindi, è “res/        ed il colore del testo, adesso, potranno essere sod-
values” (o una delle sue varianti) e il modello da         disfatte nel giro di un minuto, modificando un solo
seguire è il seguente:                                     file XML, cioè quello che contiene la definizione
                                                           dello stile.
<?xml version=”1.0” encoding=”utf-8”?>
<resources>
   <style name=”textViewStyle01”>
      <item name=”android:textStyle”>bold|italic</         EREDITÀ NEGLI STILI
                                                  item>    Chi di voi conosce il Web design, l’HTML ed i CSS
                                                           si starà sicuramente trovando a proprio agio. Il                        NOTA
     <item name=”android:textColor”>#FFFF00</item>         modello di gestione degli stili di Android, infatti,
     <item name=”android:textSize”>20sp</item>             ha fatto tesoro dell’esperienza del Web. Dai fogli di
     <item name=”android:typeface”>monospace</             stile CSS, infatti, riprende anche un’altra caratte-        FILE CONSIGLIATI
                                                  item>    ristica: l’ereditarietà. Cerchiamo di capire insieme        Stili e temi, come si è
     <item name=”android:padding”>10dp</item>              cosa significhi e quali vantaggi comporti.                  visto, vanno definiti in file
   </style>                                                Torniamo all’esempio del cliente petulante del              XML di tipo resources, da
</resources>                                                                                                           posizionare al percorso
                                                           paragrafo precedente. Nell’applicazione che stiamo          /res/values (o varianti). Non
                                                           realizzando per lui abbiamo fatto uso di numerosi           ci sono vincoli sui nomi
I singoli <item> rappresentano le proprietà che            oggetti TextView. Stando alla specifica iniziale del        dei file XML posizionabili
entrano a far parte dello stile. Nomi e valori, come       software, il testo in questi componenti deve appa-          a questo percorso, e per-
è possibile osservare, devono essere ricavati dagli        rire giallo e di una certa dimensione. Così abbiamo         tanto potete crearne quanti
                                                                                                                       ne volete e con i nomi che
attributi dei widget e dai valori che è possibile attri-   definito uno stile e lo abbiamo applicato ad ogni           più desiderate. Potete met-
buire a questi ultimi.                                     occorrenza del widget TextView. Il cliente, succes-         tere uno stile in ogni file,
In un singolo file di risorse, naturalmente, posso-        sivamente, ci ha chiesto delle modifiche, che noi           oppure fare un solo file con
no essere definiti più stili, usando più occorrenze        siamo stati in grado di apportare istantaneamente           tutti gli stili della vostra
del tag <style>. Ciascuno stile deve avere un nome         modificando lo stile applicato al testo. La soddi-          applicazione. Per Android,
                                                                                                                       in fin dei conti, è la stessa
univoco. Il nome possiamo stabilirlo noi come              sfazione del cliente è stata enorme nel constatare          cosa. La maggior parte
meglio preferiamo, certamente facendo in modo              quanto fossimo veloci ed efficienti nell’applicare la       degli sviluppatori della
che sia significativo nel nostro caso specifico. Nel       modifica richiesta. Per questo, il cliente ci ha preso      comunità Android, ad ogni
caso appena mostrato, ad esempio, si sta preparan-         gusto... Girovagando tra le schermate dell’applica-         modo, preferisce usare un
do uno stile che si intende applicare a dei widget         zione, adesso gli è venuto in mente che alcune delle        unico file styles.xml per gli
                                                                                                                       stili ed un unico file the-
TextView. Per questo si è scelto di chiamarlo text-        scritte che abbiamo modificato – solo alcune, però,         mes.xml per i temi. Spesso
ViewStyle01. Il nome potrà successivamente essere          non tutte – dovrebbero essere un po’ più piccole, ed        risulta conveniente seguire
impiegato per richiamare lo stile. Il modello da           inoltre andrebbero allineate al centro dello scher-         questa convenzione.
seguire in Java sarà:                                      mo invece che a sinistra. Contiamo fino a dieci,
                                                           sfoggiamo un sorriso compiacente, annuiamo, e
R.style.textViewStyle01                                    mettiamoci a lavoro.
                                                           Abbiamo diverse possibilità. Naturalmente non
Mentre in XML sarà:                                        possiamo modificare lo stile textViewStyle01, perché
                                                           questo significherebbe modificare tutti i TextView
@style/textViewStyle01                                     che ne fanno uso, e non solo quelle poche unità
                                                           indicate dal cliente. Potremmo allora raggiungere
Una volta pronto, lo stile può essere applicato ad         ogni occorrenza di TextView da modificare, sgan-
un widget qualsiasi attraverso il suo attributo style.     ciarla dallo stile definito in precedenza, e definire
Ad esempio:                                                su ciascuna di esse il nuovo stile usando gli attri-
                                                           buti di stile previsti da TextView. Come soluzione
<TextView                                                  funzionerebbe, ma sarebbe un passo indietro. La
    android:layout_width=”fill_parent”                     cosa migliore da fare, invece, è definire un secondo
    android:layout_height=”wrap_content”                   stile, da applicare poi in sostituzione del proce-
    android:text=”@string/message”                         dente soltanto a quelle etichette che devono essere
    style=”@style/textViewStyle01” />                      modificate. La definizione degli stili, in questo caso,


http :/ / www. i r p r o g r a m
A n d ro id p r o g oa m m ing mo. it                                                                             Luglio 2010 / 5553
                                          Android: l’utilizzo e stili
               Android programming Android: l’utilizzo di temidi temi e stili
                     MOBILE


                           diverrebbe:                                                           <item name=”android:textStyle”>bold|italic</
                                                                                                                                                   item>
                           <?xml version=”1.0” encoding=”utf-8”?>                                <item name=”android:textColor”>#00FF00</item>
                           <resources>                                                           <item name=”android:textSize”>20sp</item>
                              <style name=”textViewStyle01”>                                     <item name=”android:typeface”>monospace</
                                <item name=”android:textStyle”>bold|italic</                                                                       item>
                                                                                     item>       <item name=”android:padding”>10dp</item>
                                <item name=”android:textColor”>#00FF00</item>                   </style>
                                <item name=”android:textSize”>20sp</item>                       <style name=”textViewStyle01.PiccoloCentrato”>
                                <item name=”android:typeface”>monospace</                        <item name=”android:textSize”>16sp</item>
                                                                                     item>       <item name=”android:gravity”>center</item>
                                <item name=”android:padding”>10dp</item>                        </style>
                              </style>                                                       </resources>
                              <style name=”textViewStyle02”>
                                <item name=”android:textStyle”>bold|italic</                 In questo caso non abbiamo più uno stile text-
                                                                                     item>   ViewStyle02. Abbiamo invece definito un sotto-
                                <item name=”android:textColor”>#00FF00</item>                stile di textViewStyle01, chiamato textViewStyle01.
                                <item name=”android:textSize”>16sp</item>                    PiccoloCentrato. Questo nuovo stile è, come risulta-
                                <item name=”android:typeface”>monospace</                    to visivo finale, identico al textViewStyle02 del caso
                                                                                     item>   precedente, ma è concettualmente più corretto. Il
                                <item name=”android:padding”>10dp</item>                     solo fatto che sia un sottostile di textViewStyle01, fa
                                <item name=”android:gravity”>center</item>                   sì che dallo stile genitore vengano ereditate tutte le
                              </style>                                                       proprietà precedentemente dichiarate. All’interno
                           </resources>                                                      del sottostile, quindi, non è necessario specificare
                                                                                             il colore, il padding, il tipo di carattere o qualsiasi
                           Adesso non dobbiamo far altro che andare a ricer-                 altra proprietà in comune con il padre. All’interno
                           care quelle TextView che devono usare il secondo                  del sottostile, invece, si devono specificare soltanto
                           stile al posto del primo, ed il gioco è fatto.                    le differenze rispetto allo stile genitore, che in que-
                                                                                             sto caso sono la dimensione e l’allineamento. Se il
        NOTA                                                                                 cliente ci dovesse chiedere di tornare ad utilizzare
                                                                                             il colore giallo per le scritte, ci basterà modificare il
                                                                                             valore della proprietà android:textColor di textView-
     FULLSCREEN                                                                              Style01, e la modifica sarà propagata automatica-
 Un’attività può essere                                                                      mente anche al sottostile PiccoloCentrato.
mandata a tutto scher-                                                                       In XML ci si riferisce ad un sottostile usando la
mo applicandole il tema                                                                      notazione puntata, così come si è fatto quando lo
    Theme.NoTitleBar.      Fig. 2: Due componenti di testo con stili diversificati
             Fullscreen.                                                                     si è definito:
                           in alcune caratteristiche soltanto
                                                                                             <TextView style=”@style/textViewStyle01.
                                                                                                                                PiccoloCentrato” ... />

                           La soluzione funziona perfettamente, ma possiamo
                           fare di meglio. Guardate attentamente la definizio-               In Java, invece, il punto diventa un trattino basso
                           ne dei due stili. C’è ridondanza di informazioni e,               (underscore):
                           come sapete, ciò è male. I due stili definiti, infatti,
                           sono correlati e per questo molto simili: differiscono            R.style.textViewStyle01_PiccoloCentrato

                           solo in alcuni particolari. Il secondo stile introdot-
                           to, infatti, è solo una variazione del primo, e non               Un’altra cosa importante: non c’è un limite alla pro-
                           un vero e proprio stile a sé. Se adesso il cliente ci             fondità dell’albero dei sottostili. Se adesso il cliente
                           venisse a chiedere di cambiare di nuovo il colore del             ci dovesse chiedere di fare in modo che alcune delle
                           testo, riportandolo a giallo, dovremmo modificare                 scritte piccole centrate abbiano anche un’ombra,
                           due stili anziché uno solo, e la cosa sarebbe inna-               potremmo definire un sotto-sottostile:
                           turale proprio perché i due stili sono fortemente
                           correlati. L’ereditarietà degli stili serve proprio per           <style name=”textViewStyle01.PiccoloCentrato.

                           gestire situazioni di questo tipo:                                                                                   Ombra”>
                                                                                                <item name=”android:shadowColor”>#00FF66</
                           <?xml version=”1.0” encoding=”utf-8”?>                                                                                  item>
                           <resources>                                                          <item name=”android:shadowDx”>1.5</item>
                              <style name=”textViewStyle01”>                                    <item name=”android:shadowDy”>1.5</item>




  56
54 / Luglio 2010                                                                                                                 And roi d pr o g am m in t
                                                                                                                         h ttp ://www.io p rog rra m m o .ig
                                               Android: l’utilizzo e stili
                                        Android: l’utilizzo di temidi temi e stili                       MOBILE
                                                                                                   Android programming


   <item name=”android:shadowRadius”>1.5</item>            </application>
</style>

                                                           L’attributo android:theme può essere applicato
                                                           anche al tag <activity>, se vi interessa fare in modo
                                                           che attività differenti della stessa applicazione fac-
                                                           ciano uso di temi differenti.
                                                           Quando uno stile è applicato come tema, tutti i
                                                           widget dell’applicazione o dell’attività ne ereditano
                                                           le proprietà. Applicando il tema mostrato sopra, ad
                                                           esempio, si otterrà un’applicazione dallo sfondo
                                                           bianco e dalle scritte nere, senza la necessità di                         NOTA
                                                           associare esplicitamente ai componenti utilizzati.
                                                           Tutti i TextView, quindi, saranno automaticamente
Fig. 3: Stili e sottostili in azione                       con sfondo bianco e testo nero.                                DP E SP
                                                                                                                          Le unità di misura appli-
                                                                                                                          cabili alle dimensioni, in
                                                                                                                          Android, sono molteplici.
                                                                                                                          Tuttavia le più consigliate
TEMI                                                                                                                      sono dp e sp. La prima si
Quando si applica uno stile ad un widget, le proprie-                                                                     applica alle distanze, ed è
tà dello stile specificato influenzano solo e soltanto                                                                    praticamente una misura
il componente al quale sono state attribuite. Nessun                                                                      in pixel riscalata in base
altro widget sarà condizionato dallo stile applicato                                                                      alla densità dello schermo.
                                                                                                                          Con schermi a 160 dpi
al componente. In Android esiste però la possibilità                                                                      (densità media) 1 dp corri-
di applicare uno stile globale ad un’attività o ad                                                                        sponde ad 1 px. Se la den-
un’applicazione, facendo in modo che venga auto-                                                                          sità aumenta (ad esempio
maticamente assorbito da tutti i widget mostrati. In       Fig. 4: Applicando un tema è possibile stravolgere completa-   più di 200 dpi), però,
questo caso si dice che si utilizza un tema.               mente l’aspetto delle applicazioni                             la dimensione dei pixel
                                                                                                                          diminuisce, e per questo
Per impostare un tema per la vostra applicazione                                                                          il sistema fa in modo che
dovete per prima cosa creare uno stile. Prendiamo                                                                         1 dp diventi 2 px o più.
in considerazione il seguente:                             Non è detto che tutti i widget usati poi nell’ap-              Viceversa avviene con
                                                           plicazione supportino l’intero set di proprietà di             densità inferiori alla media.
<?xml version=”1.0” encoding=”utf-8”?>                     stile specificate nel tema. Ad esempio, i widget               Insomma, il dp è un’unità
<resources>                                                                                                               di misura che consente di
                                                           ImageView non contengono testo e, di conseguen-                preservare grosso modo
   <style name=”mioTema”>                                  za, non supportano le proprietà che impostano                  le distanze al variare della
      <item name=”android:background”>#FFFFFF</            colore, dimensione ed altri aspetti del testo. Quando          densità dei pixel nello
                                                 item>     ciò accade, il widget non fa altro che prelevare dal           schermo. L’unità sp è simi-
      <item name=”android:textColor”>#000000</item>        tema ed applicare soltanto quelle proprietà che è in           le, ma è pensata per esse-
      <item name=”android:textStyle”>bold</item>                                                                          re applicata al testo: tiene
                                                           grado di supportare.                                           infatti conto non solo della
      <item name=”android:textSize”>16sp</item>
                                                                                                                          densità dello schermo, ma
      <item name=”android:typeface”>monospace</                                                                           anche delle impostazioni
                                                 item>                                                                    dell’utente sulle dimensioni
      <item name=”android:padding”>10dp</item>             STILI E TEMI                                                   delle scritte. In un disposi-
                                                                                                                          tivo impostato per visualiz-
      <item name=”android:gravity”>top|center</item>       PREDEFINITI                                                    zare scritte molto grandi,
   </style>                                                Quando non si applicano né stili né temi, all’interno          1 sp corrisponderà ad
</resources>                                               delle nostre applicazioni, Android non fa altro che            una dimensione maggiore
                                                           usare i suoi stili ed i suoi temi predefiniti. L’aspetto       rispetto ad un sistema
Questo stile imposta uno sfondo bianco ed un testo         di ciascun widget, infatti, è definito attraverso un           con medesima densità di
                                                                                                                          schermo ma impostato con
nero, oltre a definire altre proprietà sul testo e sulla   insieme di proprietà di stile che possiamo cono-               caratteri più piccoli.
disposizione degli elementi. Per applicarlo all’inte-      scere ed esplorare. Quando si applica uno stile
ra applicazione, anziché ad un singolo elemento,           personale ad un widget, in realtà, non si fa altro che
dovete modificare AndroidManifest.xml. Là dove             sovrapporre il proprio stile a quello già predefinito
viene definita l’applicazione, fate come segue:            per quel widget. Ma quanti e quali sono gli stili
                                                           ed i temi previsti in Android? Non staremo qui ad
<application                                               elencarli uno ad uno, per motivi di spazio ma anche
   android:icon=”@drawable/icon”                           perché esistono differenze tra le diverse versioni del
   android:label=”@string/app_name”                        sistema. Potete, in base ad i vostri interessi, con-
   android:theme=”@style/mioTema”>                         sultare quali siano gli stili ed i temi previsti per una
   ...                                                     specifica piattaforma Android.


http :/ / www. i r p r o g r a m
A n d ro id p r o g oa m m ing mo. it                                                                                Luglio 2010 / 5755
                                               Android: l’utilizzo e stili
                    Android programming Android: l’utilizzo di temidi temi e stili
                          MOBILE


                                 Nel disco rigido del computer che state utilizzando             allora realizzare un’attività che appaia all’utente
                                 per sviluppare, localizzate dove avete installato               come una finestra di dialogo, facendo così nell’An-
                                 l’SDK di Android. Qui dovreste avere una directory              droidManifest.xml:
                                 chiamata “platforms”. Questa cartella contiene le
                                 diverse versioni di Android che avete scaricato ed              <activity android:theme=”@android:style/Theme.

                                 integrato nel vostro SDK. Saranno cartelle del tipo                                                                 Dialog”>

                                 “android-1”, “android-2”, “android-3” e così via,
                                 dove il numero associato alla cartella corrisponde
                                 alla revisione delle API abbinata (Android 2.1, ad
                                 esempio, è API Level 7). Scegliete la directory che             ESTENDERE GLI STILI
                                 corrisponde alla piattaforma di vostro interesse e              ED I TEMI PREDEFINITI
                                 seguite ora il percorso “data/res/values”. Qui tro-             Gli stili ed i temi predefiniti possono anche essere
                                 vate i file di risorsa predefiniti per la piattaforma           estesi. Come abbiamo appena osservato, Android
                                 Android selezionata. Per stili e temi, rispettivamen-           fornisce parecchie alternative ai temi e agli stili di
                                 te, potete consultare i file styles.xml e themes.xml.           base, ma naturalmente può capitare che neanche le
                                 Gli stili ed i temi predefiniti di Android possono              alternative incorporate soddisfino i requisiti di una
                                 essere riferiti in XML usando la sintassi:                      particolare applicazione. Ecco allora che ci ritrove-
                                                                                                 remo a dover creare il nostro tema custom. Piuttosto
                                  @android:style/NomeStile                                       che crearlo e definirlo da zero, che è un’operazione
                                                                                                 lunga e tediosa, possiamo pensare di estendere uno
                                 Il tema predefinito per le attività, ad esempio, è              dei temi incorporati, variandolo solo là dove non ci
                                 quello al percorso:                                             sta bene. Uno stile o un tema predefinito possono
                                                                                                 essere estesi osservando la seguente sintassi XML:
                                  @android:style/Theme
                                                                                                 <style name=”mioStile” parent=”@android:style/

                                 Gli stessi stili e temi sono riferibili e consultabili                                                    StilePredefinito”>

                                 anche da codice Java. Gli identificativi per ciascun               ...

                                 stile sono disponibili nella speciale classe R, non             </style>

                                 quella di progetto, ma quella di sistema, che è rife-
             L’AUTORE            ribile con il percorso android.R. Il tema principale            Ad esempio:
                                 delle attività di Android, ad esempio, può essere
                                 riferito in Java così:                                          <style name=”mioTema” parent=”@android:style/

       Carlo Pelliccia lavora                                                                                                                        Theme”>
    presso 4IT (www.4it.it),      android.R.style.Theme                                             <item name=”android:windowBackground”>@drawa
   dove si occupa di analisi                                                                                                   ble/miobackground</item>
    e sviluppo software per                                                                      </style>
    piattaforme Java. Nella      È interessante osservare come Android contenga
   sua carriera di technical     delle varianti per ciascuno stile e per ogni tema
writer ha pubblicato cinque      predefinito. Ad esempio, il tema principale Theme               Si è appena realizzato un tema uguale in tutto e
 manuali ed oltre duecento       prevede delle estensioni come Theme.Light (un                   per tutto a quello di base, fatta eccezione per lo
     articoli, molti dei quali   tema dai colori chiari), Theme.Translucent (un tema             sfondo delle finestre, che sarà realizzato servendosi
     proprio tra le pagine di
  ioProgrammo. Il suo sito,                                                                      dell’immagine raggiungibile al percorso @drawa-
   che ospita anche diversi                                                                      ble/miobackground. Non resta che applicare questo
progetti Java Open Source,                                                                       tema ad un’attività, come abbiamo imparato a fare
   è disponibile all’indirizzo                                                                   nei paragrafi precedenti:
    www.sauronsoftware.it
                                                                                                 <activity android:theme=”@style/mioTema”>


                                                                                                                                             Carlo Pelliccia


                                 Fig. 5: Un’attività con l’aspetto di una finestra di dialogo,
                                 ottenuta applicando il tema predefinito Theme.Dialog




                                 dallo sfondo trasparente), Theme.Dialog (il tema
                                 delle finestre di dialogo) ed altri ancora. Queste
                                 estensioni del tema principale sono lì proprio per              Fig. 6: Un tema costruito estendendo il tema di base di
                                 essere adoperate da noi sviluppatori. Potremmo                  Android e modificando lo sfondo e le dimensioni del testo



     58
   56 / Luglio 2010                                                                                                                   And roi d pr o g am m in t
                                                                                                                              h ttp ://www.io p rog rra m m o .ig
                                                        La gestione system
                                           MOBILE La gestione del filedel file system                          Android programming




LO STORAGING
SECONDO ANDROID
LEGGERE E SCRIVERE FILE DAL DISCO DI UNO SMARTPHONE ANDROID È UN’OPERAZIONE
POSSIBILE MA SOGGETTA A RESTRIZIONI DI SICUREZZA E A NORME DI BUON USO.
OGGI IMPAREREMO COME UTILIZZARE CORRETTAMENTE IL FILE SYSTEM DI ANDROID




                                            C
                                                    onclusa la panoramica dedicata alla rea-            fortunatamente per noi, spendono molte risorse nella
                                                    lizzazione delle UI (interfacce utente) delle       revisione del loro codice e nei test di sicurezza dello
                                                    applicazioni Android, andiamo da oggi a con-        stesso. Significa che i sistemi operativi ed i software
                                            centrarci su altri aspetti della piattaforma mobile di      che girano al loro interno, oggi, sono molto meno
                                            Google, egualmente indispensabili per applicazioni          vulnerabili rispetto a qualche anno fa. Naturalmente
                                            distribuibili e vendibili nel mondo reale. Cominciamo       non esiste e non esisterà mai un sistema o un software
                                            parlando di file system. Qualunque applicazio-              sicuro al 100%, e per questo i produttori investono
                                            ne Android, infatti, può leggere e scrivere file dalla      anche nel correggere velocemente le falle che ven-
                                            memoria interna del telefono o da una scheda esterna        gono scoperte, distribuendo poi gli aggiornamenti in
  ❑ CD ❑ WEB
  Android 153.rar                           inserita nel dispositivo. I principi da osservare per       maniera rapida e trasparente.
                                            compiere questo genere di operazioni differiscono           Sul secondo fronte, quello cioè che fa leva sul fattore
                    cdrom.ioprogrammo.it
                                            leggermente dalle normali pratiche Java adoperate           umano, la battaglia è invece un po’ più complessa ed
                                            negli applicativi desktop o server. Scopriamo insieme       arretrata. C’è chi, come Apple, richiede di approvare
                                            come fare per leggere e scrivere file dall’interno di       preventivamente qualunque applicazione prodotta
                                            un’applicazione Android.                                    per le piattaforme iPhone, iPod e iPad. L’utente può
                                                                                                        installare applicazioni solo se le preleva dallo store
                                                                                                        di Apple, che ha verificato una ad una le applicazioni
                                                                                                        disponibili, convalidandone sicurezza, attendibilità e
                                            SICUREZZA                                                   funzionalità. L’utente, così, non rischia di cadere in
                                            PRIMA DI TUTTO                                              trappola. Da una parte questo approccio risolve quasi
                                            Le piattaforme mobili di nuova generazione sono figlie      completamente il problema del fattore umano della
                                            di una ritrovata attenzione per la sicurezza dell’utente,   sicurezza, ma dall’altro limita pesantemente la libertà
                                            dei suoi dati e del suo dispositivo. I sistemi operativi    dell’utente e dei produttori di software. Insomma,
                                            per desktop, Windows in primis, sono continuamente          la cura rischia di essere peggiore del male. Android,
                                            vittima di virus e malware di ogni sorta. Questa piaga      al contrario, è permeato da una filosofia più aperta,
                                            è da sempre causa di grossa frustrazione per chi il         e per questo lascia maggiore libertà ad utenti e pro-
                                            computer lo utilizza per svago o per lavoro, pur non        grammatori, senza costringerli ad un unico canale
                                            essendone un esperto e non comprendendone i mec-            di approvvigionamento delle applicazioni. Tutto ciò,
                                            canismi interni. Siccome gli smartphone sono sempre         però, deve essere conciliato con la necessità di non far
                REQUISITI
                                            più simili ai PC, sia come potenza di calcolo sia come      proliferare il malware su questa piattaforma software.
                                            possibilità dei loro software, i produttori di sistemi      Nel caso di Android, quindi, non esiste un unico store
 Conoscenze richieste                       mobili stanno facendo il possibile per evitare che          delle applicazioni, ma ne esistono diversi. C’è quello
     Basi di Java
                                            anche le loro piattaforme possano diventare vittima         principale, l’Android Market di Google, ma per il resto
                                            di tale piaga.                                              chiunque è libero di realizzare il proprio, ed infatti
 Software
     Java SDK (JDK) 5+,                     Il software malevolo può insediarsi in un sistema in        diversi produttori lo hanno già fatto. In questo caso,
     Android SDK, Eclipse                   due differenti maniere: sfruttando una vulnerabilità        quindi, si può scegliere di chi fidarsi, godendo sia di
     3.3+, ADT
                                            interna del sistema operativo o di qualche software         una maggiore libertà sia di un senso di sicurezza basa-
 Impegno                                    che vi è installato, oppure convincendo l’utente ad         to sulla fiducia per lo store che si sta adoperando. Ad
                                            eseguire un programma che all’apparenza è inno-             ogni modo resta sempre viva la possibilità di installare
                                            cuo, ma che in realtà nasconde qualcosa di losco. Sul       applicazioni procurate anche senza la mediazione
 Tempo di realizzazione
                                            primo fronte si combatte una battaglia fatta di investi-    di uno store. È dunque necessario che il sistema sia
                                            menti sulla sicurezza del codice prodotto. I creatori di    intrinsecamente sicuro, in modo che l’utente corra
                                            Android e di tutti i sistemi operativi contemporanei,       meno rischi possibile.


        66 /Agosto 2010
A n d ro id p r o g r a m m ing                                                                                                                               57
                                                                                                                                   h ttp ://www.io pr o g r a m m o .i t
                         Android programming                      La gestione system
                                                            La gestione del filedel file system                   MOBILE


STORAGE INTERNO                                                 java.io.FileOuputStream, che può essere pertanto
Le applicazioni Android dispongono tutte di una por-            manipolato come un qualsiasi output stream di Java.
zione di spazio sul file system all’interno del quale           Si faccia pertanto riferimento alla documentazione
possono creare e leggere dei file. Tale spazio è appan-         Java per quel che riguarda l’utilizzo di stream e affi-
naggio esclusivo dell’applicazione: altri pacchetti             ni. Infine openFileOutput() può propagare una java.
installati nel dispositivo non possono farvi accesso.           io.FileNotFoundException. Ciò avviene quando il file
Insomma, ciascuna applicazione dispone di un’area               non può essere creato perché non valido.
protetta ed esclusiva all’interno della quale può fare          Il file creati con openFileOutput() possono successi-
ciò che vuole, senza però arrecare disturbo al siste-           vamente essere riletti servendosi di un altro metodo
ma o alle altre applicazioni che vi sono installate. La         messo a disposizione da Context:
classe android.content.Context, che è quella da cui
derivano Activity e tutti gli altri mattoni fondamentali        public abstract FileInputStream openFileInput
di Android, dispone di una serie di metodi utili per            (String name)
interagire con la porzioni di file system esclusiva-            throws FileNotFoundException
mente assegnata all’applicazione. Per scrivere un file
all’interno dell’area è disponibile il metodo:                  Il parametro name, come è facile immaginare,
                                                                è il nome del file da recuperare. L’eccezione java.                        NOTA
public FileOutputStream openFileOutput(String                   io.FileNotFoundException viene propagata se il file
name, int mode)                                                 richiesto non esiste. L’oggetto restituito è un input
throws FileNotFoundException                                    stream standard di tipo java.io.FileInputStream.              ANDROID 2.2
                                                                Questo oggetto, come nel caso precedente, può essere          Se siete appassionati di
Il parametro name è il nome del file da scrivere, men-          utilizzato secondo la comune prassi Java per la lettura       Android, certamente la
                                                                                                                              notizia non vi sarà sfuggi-
tre il parametro mode può essere:                               dei contenuti del file. I file non più utili possono essere   ta: è stato da poco rilascia-
                                                                cancellati con il metodo:                                     to Android 2.2, nome in
•	 Context.MODE_PRIVATE                                                                                                       codice Froyo. Le principali
   Rende il file privato, cioè appannaggio esclusivo            public boolean deleteFile(String name)                        novità di questa release
   dell’applicazione che lo sta scrivendo. Nessun’altra                                                                       riguardano le presentazio-
                                                                                                                              ne della macchina virtuale
   applicazione potrà vederlo, leggerlo o sovrascri-            In questo caso non ci sono eccezioni da gestire, ma il        Dalvik: grazie all’introdu-
   verlo.                                                       metodo restituisce un booleano per indicare se il file        zione della compilazione
                                                                specificato è stato effettivamente rimosso oppure no.         JIT (Just In Time) il codice
•	 Context.MODE_APPEND                                          Infine i file conservati nell’area riservata all’applica-     Java riesce a correre fino
   Agisce in append sul file specificato, cioè se il file       zione possono essere elencati con il metodo:                  al 400% più velocemente!
                                                                                                                              Dal punto di vista di noi
   già esiste, invece di sovrascriverlo, gli accoda i                                                                         sviluppatori, ci sono anche
   nuovi byte che saranno scritti nello stream. Utile           public String[] fileList()                                    novità a livello delle inter-
   quando si generano report e log.                                                                                           facce di programmazione,
                                                                Il metodo restituisce un array con i nomi di tutti i file     che hanno raggiunto l’API
•	 Context.MODE_WORLD_READABLE                                  associati all’applicazione.                                   Level 8. Simultaneamente
                                                                                                                              è stata rilasciata anche la
   Rende il file accessibile in sola lettura dalle altre                                                                      versione R6 dell’SDK e la
   applicazioni installate nel sistema.                                                                                       0.9.7 del plug-in ADT per
                                                                                                                              Eclipse. Aggiornate pertan-
•	 Context.MODE_WORLD_WRITEABLE                                 REALIZZIAMO                                                   to tutti i vostri ambienti alle
   Rende il file accessibile in sola scrittura dalle altre      UN BLOCCO NOTE                                                nuove versioni.
   applicazioni installate nel sistema.                         Realizziamo insieme un’applicazione dimostrativa in
                                                                grado di scrivere e leggere da un file conservato nello
Due o più costanti possono essere applicate contem-             spazio riservato all’applicazione stessa. Realizzeremo
poraneamente con l’operatore binario OR (simbolo:               una specie di blocco note, che l’utente potrà utilizzare
pipe). Ad esempio se si vuole generare un file privato          per prendere appunti. Gli appunti saranno salvati su
in append si può fare:                                          un file interno all’applicazione, che l’utente potrà suc-
                                                                cessivamente richiamare. Chiameremo l’applicazione
Context.PRIVATE | Context.APPEND                                ed il corrispondente progetto “FileDemo01”. Partiamo
                                                                definendo le seguenti risorse su res/values/strings.xml:
Un file condiviso con le altre applicazioni sia in lettura
che in scrittura, invece, dovrà avere modo:                      <?xml version=”1.0” encoding=”utf-8”?>
                                                                 <resources>

Context.MODE_WORLD_READABLE                   |   Context.         <string name=”app_name”>FileDemo01</string>

MODE_WORLD_WRITEABLE                                               <string name=”saveButton”>Salva</string>
                                                                   <string name=”loadButton”>Carica</string>

Il metodo openFileOutput() restituisce un oggetto                </resources>




    58
http :/ / w ww. i o p r o g r a m m o. it                                                                               Agosto And roi d pr o67 m in g
                                                                                                                               2010 / g r am
                                   MOBILE                    La gestione del file system
                                                       La gestione del file system                                   Android programming


                                    A queste affianchiamo il seguente layout da posizio-                         @Override

                                    nare su res/layout/main.xml:                                                 public void onClick(View v) {
                                                                                                                      load(“testo.txt”);
                                    <?xml version=”1.0” encoding=”utf-8”?>                                       }
                                    <LinearLayout xmlns:android=”http://schemas.android.                       });
                                                                                com/apk/res/android”       }
                                          android:layout_width=”fill_parent”                               private void save(String filename) {
                                          android:layout_height=”fill_parent”                                  EditText textArea = (EditText) findViewById
                                          android:orientation=”vertical”>                                                                                    (R.id.textArea);
                                          <LinearLayout android:layout_width=”fill_parent”                     String text = textArea.getText().toString();
                                           android:layout_height=”wrap_content”                                Writer writer = null;
                                           android:orientation=”horizontal”>                               ...
                                           <Button android:layout_width=”wrap_content”
                                                android:layout_height=”wrap_content”                    L’attività gestisce il file riservato testo.txt attraverso i
                                                android:id=”@+id/saveButton”                            due metodi load() e save(), richiamati alla pressione
                                                android:text=”@string/saveButton” />                    dei due bottoni disposti nel layout. Il testo viene letto
                                           <Button android:layout_width=”wrap_content”                  e scritto servendosi delle astrazioni Reader e Writer di
                                                android:layout_height=”wrap_content”                    Java (cfr. box laterale), utili quando si ha a che fare con
               NOTA
                                                android:id=”@+id/loadButton”                            file di natura testuale.
                                                android:text=”@string/loadButton” />                    Sul CD-Rom allegato alla rivista troverete sia l’esem-
 READER E WRITER                          </LinearLayout>                                               pio completo dell’applicazione “FileDemo01”, sia una
          java.io.Reader e java.          <EditText android:layout_width=”fill_parent”                  seconda applicazione “FileDemo02” che usa il metodo
 io.Writer sono le astrazioni              android:layout_height=”fill_parent”                          fileList() e delle finestre di dialogo per far consentire
          di base di Java per la           android:id=”@+id/textArea”                                   all’utente di scegliere il nome del file da salvare o da
      lettura e la scrittura dei           android:inputType=”textMultiLine”
   testi. A differenza di java.                                                                         caricare.
                                           android:gravity=”top|left” />
         io.InputStream e java.
          io.OutputStream, che      </LinearLayout>
       ragionano in termini di
     byte, i reader ed i writer
  trattano caratteri, sequen-
                                    Questo layout riempie il display con una casella di                 STORAGE ESTERNO
        ze di caratteri e perciò    testo, all’interno della quale l’utente potrà appuntare             I dispositivi Android possono disporre di un secon-
      stringhe. Passare da un       le proprie note. Al di sopra di essa sono stati dispo-              do spazio di storage, definito “storage esterno”.
  InputStream ad un Reader          sti i due pulsanti “Salva” e “Carica”, utili rispettiva-            Solitamente lo storage esterno è una scheda che può
    è sempre possibile attra-       mente per memorizzare e per richiamare successi-                    all’occorrenza essere rimossa e sostituita, ma non è
 verso la classe ponte java.        vamente il testo digitato. Realizziamo ora l’attività               detto: in alcuni casi lo storage esterno è comunque
        io.InputStreamReader.
              Per passare da un     it.ioprogrammo.filedemo01.FileDemo01Activity, inca-                 interno al dispositivo e non rimovibile. A priori, ad
OutputStream ad un Writer,          ricata di realizzare la logica di scrittura e lettura del file      ogni modo, non è dato saperlo.
     invece, ci vuole un java.      su comando dell’utente:                                             Pertanto la prima cosa da farsi quando si vuole acce-
       io.OutputStreamWriter.                                                                           dere allo storage esterno, è controllare se questo è
                                    package it.ioprogrammo.filedemo01;                                  disponibile. Il metodo utile per farlo è contenuto sta-
                                    ...                                                                 ticamente nella classe android.os.Environment, ed è:
                                    public class FileDemo01Activity extends Activity {
                                          @Override                                                     public static String getExternalStorageState()
                                          public void onCreate(Bundle savedInstanceState) {
                                           super.onCreate(savedInstanceState);                          La stringa restituita può essere confrontata con una
                                           setContentView(R.layout.main);                               delle seguenti costanti:
                                           Button saveButton = (Button) findViewById
                                                                                   (R.id.saveButton);   •	 Environment. MEDIA_MOUNTED
                                           saveButton.setOnClickListener(new View.                        Lo storage esterno è disponibile e pronto.
                                                                                 OnClickListener() {
                                                @Override                                               •	 Environment. MEDIA_MOUNTED_READ_ONLY
                                                public void onClick(View v) {                             Lo storage esterno è disponibile e pronto, ma è
                                                    save(“testo.txt”);                                    possibile accedervi in sola lettura.
                                                }
                                           });                                                          •	 Environment. MEDIA_UNMOUNTED
                                           Button loadButton = (Button) findViewById                      Environment. MEDIA_UNMOUNTABLE
                                                                                   (R.id.loadButton);     Environment. MEDIA_BAD_REMOVAL
                                           loadButton.setOnClickListener(new View.w()                     Environment. MEDIA_CHECKING
                                            {                                                             Environment. MEDIA_NOFS


        68 /Agosto 2010
A n d ro id p r o g r a m m ing                                                                                                                                        59
                                                                                                                                           h ttp ://www.io p r o g r a m m o .i t
                         Android programming                         La gestione system
                                                               La gestione del filedel file system                           MOBILE


     Environment. MEDIA_REMOVED                                     ORGANIZZAZIONE DELLO
     Environment. MEDIA_SHARED                                      STORAGE ESTERNO
     Queste altre costanti rappresentano stati di errore            Quando si utilizza lo storage esterno, ci sono delle
     per cui, per un motivo o per un altro, lo storage              norme che è opportuno seguire. Ad esempio si scon-
     esterno non è disponibile. La documentazione uffi-             siglia di creare file direttamente nella radice dello
     ciale approfondisce ciascuno di questi stati.                  storage. Android infatti organizza il suo storage ester-
                                                                    no con una serie di directory standard che, in molti
Solitamente, prima di accedere allo storage esterno, si             casi, è conveniente utilizzare. Queste solitamente
usa una routine del tipo:                                           sono:                                                                             NOTA
 boolean possoLeggereStorageEsterno = false;                        •	 Music, per la musica.
 boolean possoScrivereStorageEsterno = false;                       •	 Podcasts, per i podcast.                                          DOVE SI TROVA
 String state = Environment.getExternalStorageState();              •	 Ringtones, per le suonerie.                                       LO STORAGE
 if (Environment.MEDIA_MOUNTED.equals(state)) {                     •	 Alarms, per i suoni da abbinare agli allarmi.                     DELLA MIA APP?
      // Storage esterno disponibile in lettura e scrittura.        •	 Notifications, per i suoni da abbinare alle notifiche.            È possibile scoprire quale
      possoLeggereStorageEsterno = possoScrivereStora               •	 Pictures, per le foto (escluse quelle fatte con la foto-          sia la directory radice dello
                                               geEsterno = true;      camera del dispositivo).                                           spazio riservato ad un’ap-
                                                                                                                                         plicazione, chiamando il
 } else if (Environment.MEDIA_MOUNTED_READ_ONLY.                    •	 Movies, per i video (esclusi quelli ripresi con la vide-          metodo di Context getFile-
                                                 equals(state)) {     ocamera del dispositivo).                                          sDir(). Il metodo restituisce
      // Storage esterno disponibile solo in lettura.               •	 Download, per i file scaricati.                                   un oggetto di tipo java.
      possoLeggereStorageEsterno = true;                                                                                                 io.File. Stampando il per-
      possoScrivereStorageEsterno = false;                          Seguendo questa convenzione diventa molto sempli-                    corso della directory chia-
 } else {                                                                                                                                mandone il metodo di File
                                                                    ce condividere dati con le altre applicazioni installate             getAbsolutePath(), scopri-
     // Storage esterno non disponibile.                            nel sistema. Ad esempio è possibile realizzare un’at-                rete un risultato del tipo:
      possoLeggereStorageEsterno = possoScrivereStora               tività in grado di mostrare le immagini memorizzate
                                               geEsterno = false;   nella card esterna, alla seguente maniera:                           /data/data/<package appli-
 }                                                                                                                                       cazione>/files
                                                                    package it.ioprogrammo.filedemo04;

Una volta che ci si è accertati che sia possibile accedere          ...                                                                  Con la prospettiva DDMS
allo storage esterno, è possibile farlo recuperandone il            public class FileDemo04Activity extends Activity {                   di Eclipse, inoltre, potrete
percorso attraverso il metodo statico di Environment:                                                                                    esplorare il file system
                                                                          public void onCreate(Bundle savedInstanceState) {              dell’emulatore o di un
                                                                                                                                         dispositivo collegato,
public static File getExternalStorageDirectory()                              super.onCreate(savedInstanceState);
                                                                                                                                         andando così a verificare
                                                                              setContentView(R.layout.main);                             dove sono i file e di quale
Il metodo restituisce un oggetto java.io.File che rap-                        Drawable[] pictures;                                       permessi dispongono.
presenta la radice dello storage esterno. Usando le                           if (canReadFromExternalStorage()) {

comuni API I/O di Java, a questo punto, è possibile                               pictures = loadPicturesFromExternalStorage();

navigare lo storage esterno, creare nuovi file, leggere                       } else {

quelli esistenti e così via, senza alcuna limitazione.                            pictures = new Drawable[0];

Sul CD trovate una rivisitazione del blocco note usato                        }

come caso di studio nel paragrafo precedente. Questa                          ImageAdapter adapter = new ImageAdapter(this,
                                                                                                                                                     L’AUTORE
terza implementazione del software salva gli appunti                                                                        pictures);

dell’utente sullo storage esterno.                                            Gallery gallery = (Gallery) findViewById(R.
                                                                                                                       id.myGallery);    Carlo Pelliccia lavora
                                                                              gallery.setAdapter(adapter);                               presso 4IT (www.4it.it),
                                                                          }                                                              dove si occupa di analisi
                                                                                                                                         e sviluppo software per
                                                                                                                                         piattaforme Java. Nella
                                                                          private boolean canReadFromExternalStorage() {
                                                                                                                                         sua carriera di technical
                                                                              String state = Environment.getExternalStorageState();      writer ha pubblicato cinque
                                                                              if (Environment.MEDIA_MOUNTED.equals(state)) {             manuali ed oltre duecento
                                                                                  return true;                                           articoli, molti dei quali
                                                                          ...                                                            proprio tra le pagine di
                                                                                                                                         ioProgrammo. Il suo sito,
                                                                                                                                         che ospita anche diversi
                                                                    L’esempio completo lo trovate nel CD-Rom. Nel prossi-                progetti Java Open Source,
                                                                    mo numero impareremo a mettere un database all’in-                   è disponibile all’indirizzo
                                                                    terno delle nostre applicazioni Android!                             www.sauronsoftware.it
Fig. 1: L’applicazione “FileDemo01” realizza una specie
di semplice blocco per gli appunti
                                                                                                                      Carlo Pelliccia



     60
http :/ / w ww. i o p r o g r a m m o. it                                                                                          Agosto And roi d pr o69 m in g
                                                                                                                                          2010 / g r am
                                        MOBILE            Android: l’accesso al
                                                       Android: l’accesso al DB DB                   Android programming




DATABASE
DA TASCHINO
UNA DELLE CARATTERISTICHE PIÙ INTERESSANTI DI ANDROID È IL DBMS INTEGRATO
NEL SISTEMA, CHE DOTA LE APPLICAZIONI DELLA CAPACITÀ DI ARCHIVIARE E RICERCARE
VELOCEMENTE I DATI. IN QUESTO ARTICOLO IMPAREREMO COME APPROFITTARNE




                                         D
                                                  BMS, ossia Database Management              a coSa SeRVe?
                                                  System, è un termine caro agli svilup-      È lecito chiedersi che ruolo possa avere un
                                                  patori di applicazioni server-side e di     DBMS installato in un telefono cellulare. Le
                                         impresa. La maggior parte delle applicazioni         applicazioni mobili, infatti, non gestiscono
                                         Web, ad esempio, si appoggiano ad un databa-         grandi quantità di dati, e nemmeno devono
                                         se, e lo utilizzano per organizzare e ricercare      soddisfare il requisito dell’accesso contem-
                                         velocemente dati di ogni tipo. È naturale che        poraneo da parte di un elevato numero di
                                         le applicazioni server-side abbiano bisogno di       utenti. I DBMS, invece, servono proprio per
                                         un DBMS, visto che devono gestire grosse moli        soddisfare la necessità di scrivere e leggere
  ❑ cd ❑ Web
  NotePad.rar                            di dati, come l’elenco degli utenti iscritti ad un   molti dati, e soprattutto lo possono fare in tante
                                         sito, o gli articoli pubblicati in un blog, i com-   sessioni simultanee (si pensi a quante visite
                 cdrom.ioprogrammo.it
                                         menti dei visitatori, le statistiche di accesso e    contemporanee può raggiungere un sito Web).
                                         così via. Insomma, anche le più semplici appli-      Un’applicazione mobile, da questo punto di
                                         cazioni server fanno solitamente uso intensivo       vista, potrebbe tranquillamente accontentarsi
                                         dei database.                                        di salvare le proprie informazioni in uno o più
                                         Le applicazioni client-side per desktop, diver-      file di testo, come d’altronde è stato già spie-
                                         samente, usano i DBMS assai meno di frequen-         gato nel numero precedente. Perché allora si
                                         te. Esistono dei DBMS specifici per personal         dovrebbe usare un DBMS?
                                         computer, come Access di Microsoft, ed alcuni        Tanto per cominciare, lo si fa perché con un
                                         di quelli usati lato server si comportano bene       DBMS è tutto più facile. In un database, infat-
                                         anche se installati su un desktop o un laptop        ti, i dati possono essere strutturati e tipizzati.
                                         (MySQL, ad esempio). In questo caso i DBMS           Immaginiamo di dover realizzare un’applica-
                                         vengono utilizzati soprattutto in applicazioni       zione che gestisca una lista di contatti, tipo
                                         specifiche, spesso realizzate ad hoc per par-        un’agenda. Ogni contatto è caratterizzato da
                                         ticolari situazioni ed utenti. Ad esempio un         un identificativo (ID), un nome, un cognome
                                         gestionale per un libero professionista, o qual-     e un indirizzo. Se dovessimo salvare queste
                                         che altro software del genere, può fare ricorso      informazioni su un file di testo, dovremmo
                                         ad un DBMS locale.                                   inventare un formato e programmare poi le
                                         Passando al mondo mobile, invece, “DBMS” e           classi in grado di gestirlo. La soluzione più
                REQUISITI
                                         “database” sono parole dal suono alieno e fuori      classica consiste nell’organizzare un contatto
                                         contesto. Almeno fino a ieri.                        per ciascuna riga, separando poi i campi con
Conoscenze richieste                     Gli smartphone di nuova generazione, infatti,        una virgola. Ad esempio:
    Basi di Java
                                         hanno raggiunto potenza di calcolo e com-
                                         plessità software sufficienti per l’esecuzione       1,Mario,Rossi,061299178
Software
    Java SDK (JDK) 5+,                   di un DBMS di piccole dimensioni, ottimiz-           2,Antonio,Verdi,028667661
    Android SDK, Eclipse                 zato appositamente per un ambito peculia-
    3.3+, ADT
                                         re e ristretto. Android comprende un piccolo         I dati di un contatto, inoltre, non sono soltanto
Impegno                                  DBMS, che gli sviluppatori possono richiamare        di natura testuale: nome, cognome, e numero di
                                         per salvare ed organizzare i dati delle loro         telefono sono delle stringhe, ma l’identificativo
                                         applicazioni. In questo articolo scopriremo          del contatto è certamente un intero, e va gesti-
Tempo di realizzazione
                                         come funziona questo DBMS. Vedremo come              to come tale. Nel leggere e nel salvare i dati,
                                         utilizzarne i benefici per rendere migliori e più    quindi, bisognerebbe fare un sacco di lavoro di
                                         complete le nostre applicazioni.                     codifica e decodifica, sia per gestire la struttura


        54 / Settembre 2010
A n d ro id p r o g r a m m ing                                                                                                                    61
                                                                                                                       h ttp ://www.io p r o g r a m m o .i t
                         Android programming         Android: l’accesso al DB DB
                                                        Android: l’accesso al                            MOBILE


del file sia per una corretta interpretazione dei     RichiamaRe
tipi coinvolti.                                       un databaSe
Con un database, invece, è tutto più sempli-          Nella libreria di Android, i package Java di
ce: si crea una tabella con tanti campi quanti        riferimento per l’accesso ai database e l’utiliz-
sono quelli necessari, ognuno già abbinato al         zo di SQLite sono, rispettivamente, android.
tipo più consono. Le operazioni di lettura e          database e android.database.sqlite. I database,
scrittura, servendosi della libreria di accesso       in Android, funzionano con la stessa logica
al DBMS, necessitano ora di pochissime righe          di accesso e protezione dei file (cfr. numero
di codice. Non è solo un fatto di fatica rispar-      precedente): ogni applicazione crea ed utilizza
miata, ma è anche una questione di sicurezza          uno o più database in maniera esclusiva.
ed efficienza.                                        I database creati da un’applicazione non pos-
Un altro settore nel quale è difficile compe-         sono essere letti dalle altre applicazioni. La
tere con un DBMS è quello delle ricerche:             condivisione di dati strutturati fra più appli-
nell’agenda basata su file di testo bisognerebbe      cazioni Android, infatti, avviene mediante un
implementare degli algoritmi per la ricerca dei       ulteriore meccanismo, quello dei provider, che
contatti. È possibile farlo, ma un buon algorit-      analizzeremo in futuro. Ciascuna applicazione,
mo di ricerca, che allo stesso tempo sia tanto        quindi, ha i suoi database, e nessun altro può
veloce quanto poco pretenzioso di risorse, non        accedervi.
è una cosa semplice. Considerando che un              La pratica di programmazione consigliata per
DBMS contiene il risultato di anni di sviluppo        l’accesso ad un database passa per l’esten-                                 NOTA
nel settore delle ricerche ottimizzate, ecco che      sione della classe android.database.sqlite.
l’ago della bilancia si sposta ulteriormente          SQLiteOpenHelper. Il modello da seguire è il                   SQL
dalla parte dei database.                             seguente:                                                      È impossibile avere a che
Tutto ciò non significa, naturalmente, che                                                                           fare con un DBMS senza
qualsiasi applicazione Android debba usare il          package mia.applicazione;                                     masticare un po’ di SQL,
                                                                                                                     il linguaggio principe per
DBMS. La possibilità comunque c’è, e convie-                                                                         l’utilizzo dei database.
ne sfruttarla in tutte quelle applicazioni che         import android.content.Context;
                                                                                                                     Questo linguaggio, almeno
hanno bisogno di scrivere, leggere e fare ricer-       import android.database.sqlite.SQLiteDatabase;                per quello che riguarda
che su insiemi di dati strutturati.                    import android.database.sqlite.SQLiteOpenHelper;              l’utilizzo quotidiano e non
                                                                                                                     avanzato, è piuttosto sem-
                                                       public class MioDatabaseHelper extends                        plice e consiste di pochi
                                                                                                                     costrutti per l’interrogazio-
                                                       SQLiteOpenHelper {
                                                                                                                     ne e la manipolazione dei
SQLite                                                                                                               dati. Insomma, se non ne
Il DBMS integrato in Android arriva dal mondo          	 private	static	final	String	DB_NAME	=	“nome_db”;            sapete nulla non dovete
dell’Open Source. Si tratta di SQLite, che nella       	 private	static	final	int	DB_VERSION	=	1;                    disperare: l’SQL di base
                                                                                                                     si impara facilmente ed in
costellazione dei DBMS si distingue per leg-                                                                         poco tempo. Cominciate
gerezza e facilità di integrazione. Traducendo             public MioDatabaseHelper(Context context) {
                                                                                                                     con qualche tutorial online,
letteralmente quanto è possibile leggere nella         	 	 super(context,	DB_NAME,	null,	DB_VERSION);                come ad esempio questo:
home page del progetto: “SQLite è una libreria             }                                                         http://database.html.it/
che implementa un motore di database SQL                                                                             guide/leggi/40/guida-
transazionale auto-sufficiente, senza server e             @Override                                                 linguaggio-sql/
senza bisogno di configurazione”. SQLite è                 public void onCreate(SQLiteDatabase db) {

scritto in C e la sua distribuzione ufficiale fun-             // Creazione delle tabelle

ziona su Linux, Mac OS X e Windows. Per uti-               }

lizzarlo su Android, comunque, non bisogna né
compilare né installare nulla: è tutto compreso            @Override

nel sistema operativo stesso. Gli sviluppatori             public void onUpgrade(SQLiteDatabase db,

di Google, come vedremo tra poco, hanno                	 int	oldVersion,	int	newVersion)	{

anche realizzato le interfacce di programma-           	 	 //	Aggiornamento	delle	tabelle

zione Java utili per richiamare ed utilizzare i            }

database dall’interno di una qualsiasi applica-
zione Android. Insomma, leggere e scrivere un          }

database, in Android, è un’operazione nativa
e incorporata, come lo è accedere ad un file          Si deve creare una classe di questo tipo per
o connettersi alla rete. L’unico prerequisito         ciascun database necessario alla propria appli-
richiesto è la conoscenza, anche basilare, di         cazione. Nelle due costanti DB_NAME e DB_
SQL, il linguaggio principe per l’interazione         VERSION vanno indicati, rispettivamente, il
con i DBMS (cfr. box laterale).                       nome del database (inutile dire che ogni data-



    62
h ttp :/ / www. i o p r o g r a m m o. it                                                                          2010 / 55
                                                                                                         Settembre And roi d pr o g r am m in g
                                   MOBILE              Android: l’accesso al
                                                    Android: l’accesso al DB DB                 Android programming


                                    base di una stessa applicazione deve avere un       popolati automaticamente quando si aggiunge
                                    nome differente, così come differente deve          un nuovo record, con una sequenza progressi-
                                    essere il nome della classe helper) e la sua        va di interi, funzionando quindi da contatore.
                                    versione. Il numero di versione è un intero che     Lo speciale nome _id, poi, serve ad Android
                                    va incrementato ogni volta che, in un nuovo         per capire quale è il campo identificativo di
                                    rilascio del software, il database viene modifi-    ciascun record.
                                    cato nella struttura. In questa maniera, quando     Seguendo questa prassi, le vostre tabelle saran-
                                    l’utente aggiorna la propria applicazione, la       no perfettamente integrate nella gestione auto-
                                    classe riesce a capire se il database della ver-    matica offerta dal sistema.
                                    sione precedentemente installata deve essere        Una volta completato lo sviluppo della classe
                                    aggiornato oppure no.                               helper, è possibile sfruttarla in qualsiasi punto
                                    I due metodi onCreate() e onUpdate() devono         dell’applicazione. Tipicamente, nello sviluppo
                                    necessariamente essere implementati. Il primo       di una activity, si tende a conservare l’helper
                                    viene richiamato quando il database deve esse-      a livello di istanza, avendo cura di istanziarlo
                                    re creato per la prima volta. Il parametro db, di   la prima volta in risposta all’evento onCreate()
                                    tipo android.database.sqlite.SQLiteDatabase,        dell’attività. Il modello è il seguente:
                                    serve per poter manipolare il database appe-
                                    na creato. Tra poco vedremo come. Il metodo         package mia.applicazione;

                                    onCreate() viene richiamato quando l’appli-
                                    cazione è stata appena installata. Il metodo        import	android.app.Activity;
                NOTA                onUpdate(), invece, viene richiamato quando il      import	android.os.Bundle;

                                    database è già presente sul sistema, ma stando
                       SQLITE       al numero di versione richiesta, risulta obso-      public	class	MiaAttivita	extends	Activity	{

   Il sito di riferimento per       leto. Di solito avviene dopo aver cambiato la
        SQLite è disponibile        versione di un’applicazione già installata.             private MioDatabaseHelper mioDatabaseHelper;
                  all’indirizzo:    I parametri oldVersion e newVersion, come è
            www.sqlite.org/                                                                 @Override
  La documentazione sulle           facile indovinare, indicano rispettivamente la
                                    versione già installata del database e quella       	 public	void	onCreate(Bundle	savedInstanceState)	{
 funzionalità supportate da
 SQLite e sulla loro sintassi       ancora da installare.                               	 	 super.onCreate(savedInstanceState);
        d’uso è all’indirizzo:      Le tabelle di un database, in SQLite come in        	 	 mioDatabaseHelper	=	new	MioDatabaseHelper(this);
  www.sqlite.org/docs.html          tutti i principali DBMS, debbono essere cre-            }

                                    ate con delle istruzioni SQL di tipo CREATE
                                    TABLE, oppure aggiornate con ALTER TABLE.           }

                                    Come appena detto, è necessario farlo all’inter-
                                    no dei metodi onCreate() e onUpdate().              In qualsiasi punto dell’attività, adesso, è possi-
                                    Gli oggetti di tipo SQLiteDatabase dispongo-        bile utilizzare l’helper e domandargli l’accesso
                                    no di un metodo execSQL(), che permette di          al database. Lo si può fare con i metodi getRea-
                                    eseguire del codice SQL arbitrario. È proprio       dableDatabase() e getWritableDatabase():
                                    quello che fa al caso nostro! Ad esempio:
                                                                                        SQLiteDatabase	db	=	mioDatabaseHelper.get
                                    @Override                                                                                  ReadableDatabase();
                                    public void onCreate(SQLiteDatabase db) {
                                    	 String	sql	=	“”;                                  oppure
                                    	 sql	+=	“CREATE	TABLE	agenda	(“;
                                    	 sql	+=	“		_id	INTEGER	PRIMARY	KEY,”;              SQLiteDatabase	db	=	mioDatabaseHelper.
                                    	 sql	+=	“		nome	TEXT	NOT	NULL,”;                                                       getWritableDatabase();
                                    	 sql	+=	“		cognome	TEXT	NOT	NULL,”;
                                    	 sql	+=	“		telefono	TEXT	NOT	NULL”;                Con getReadableDatabase() si ottiene l’accesso
                                    	 sql	+=	“)”;                                       al database in sola lettura; con getWritable-
                                        db.execSQL(sql);                                Database() si ottiene invece la possibilità di
                                    }                                                   scrivere nel database, per inserire, aggiornare
                                                                                        o cancellare record dalle tabelle. In ambo i casi
                                    In questo codice si è creata una tabella chia-      l’oggetto restituito è di tipo android.database.
                                    mata “agenda”, con i campi citati nell’esempio      sqlite.SQLiteDatabase. Nei prossimi paragrafi
                                    usato in precedenza. Un trucco ed un consiglio:     passeremo in rassegna i principali metodi di
                                    dotate sempre le vostre tabelle di una chiave       questa categoria di oggetti, utili per scrivere e
                                    primaria numerica. I campi di tipo INTEGER          leggere i record presenti nelle tabelle del data-
                                    PRIMARY KEY, in SQLite, vengono sempre              base recuperato.


        56 / Settembre 2010
A n d ro id p r o g r a m m ing                                                                                                                  63
                                                                                                                     h ttp ://www.io p r o g r a m m o .i t
                         Android programming                      Android: l’accesso al DB DB
                                                                     Android: l’accesso al                           MOBILE


inSeRiRe, aggioRnaRe                                                int	r	=	db.update(“agenda”,	values,	whereClause,	null);
e canceLLaRe i RecoRd
Gli oggetti SQLiteDatabase espongono un                            La seconda tattica consiste invece nell’usare
metodo di convenienza per l’inserimento di un                      dei segni di punto interrogativo in whereClau-
nuovo record in una tabella:                                       se, a cui far poi corrispondere degli argomenti
                                                                   nell’array di stringhe whereArgs:
public long insert(String table, String
                        nullColumnHack,	ContentValues	values)       SQLiteDatabase	db	=	mioDatabaseHelper.getWritable
                                                                                                                 Database();

L’argomento table è il nome della tabella in cui                    ContentValues	values	=	new	ContentValues();

inserire il nuovo record; nullColumnHack è un                       values.put(“telefono”,	“068390239”);

valore che nella maggior parte dei casi va posto
su null, visto che serve solo nel caso particola-                   String	whereClause	=	“nome	=	?	AND	cognome	=	?”;

re in cui si crea un record senza specificare i                     String[]	whereArgs	=	{	“Mario”,	“Rossi”	};

suoi valori iniziali; values è la mappa dei valori                  int	r	=	db.update(“agenda”,	values,	whereClause,

iniziali da salvare nel record, di tipo android.                                                                whereArgs);

content.ContentValues. Il metodo restituisce un
valore long, che è l’ID del record appena creato,                  Questa seconda pratica è generalmente da pre-
oppure è -1 se il record non è stato creato. Ecco                  ferirsi, perché evita le ambiguità (e le vulne-
un esempio:                                                        rabilità) dovute all’utilizzo degli apici come
                                                                   delimitatori delle stringhe SQL (cercate “sql                              NOTA
SQLiteDatabase	db	=	mioDatabaseHelper.getWritable                  injection” su Google per approfondire).
                                                   Database();     È anche possibile passare null sia su whereClau-               TIPI DI DATI
ContentValues	values	=	new	ContentValues();                        se che su whereArgs: in questo caso saranno                    IN SQLITE
                                                                   aggiornati tutti i record presenti nella tabella.              I tipi di dati supportati da
values.put(“nome”,	“Mario”);                                       In ogni caso, il metodo update() restituisce un                SQLite sono descritti nel
values.put(“cognome”,	“Rossi”);                                    intero, che indica proprio quanti sono i record                documento:
values.put(“telefono”,	“061299178”);                                                                                              www.sqlite.org/datatype3.
                                                                   aggiornati mediante l’esecuzione dell’istruzio-                html
long	id	=	db.insert(“agenda”,	null,	values);                       ne. Per cancellare uno o più record è a disposi-
                                                                   zione il metodo delete():
L’aggiornamento dei dati contenuti in un
record è possibile grazie al metodo update(),                       public	int	delete(String	table,	String	whereClause,

così definito:                                                                                          	String[]	whereArgs)


public	int	update(String		table,	ContentValues	                    L’utilizzo di delete() è simile ad update(), con la
            values,	String	whereClause,	String[]	whereArgs)        sola differenza che in questo caso non ci sono
                                                                   nuovi valori da sovrascrivere ai precedenti,
Come nel caso precedente, table è il nome                          visto che si tratta di un’operazione di cancella-
della tabella e values è la mappa dei campi da                     zione e non di aggiornamento.
aggiornare con i nuovi valori da assegnare. Gli                    Ad esempio:
argomenti whereClause e whereArgs servono
per selezionare il record o i record da aggiorna-                   SQLiteDatabase	db	=	mioDatabaseHelper.

re. Sono sostanzialmente delle clausule WHERE                                                        getWritable Database();

di SQL, da comporre secondo le comuni regole                        String	whereClause	=	“_id	=	?”;

del linguaggio.                                                     String[]	whereArgs	=	{	“1”	};

Si può procedere in due modi. Immaginiamo                           int	r	=	db.delete(“agenda”,	whereClause,	whereArgs);

di volere modificare il numero di telefono in
agenda per la voce “Mario Rossi”.                                  Altre istruzioni di scrittura su database, come
Il primo modo consiste nello scrivere l’intera                     per esempio quelle di gestione delle tabelle,
clausola di tipo WHERE sull’argomento where-                       possono invece essere eseguite passando diret-
Clause, tenendo su null l’argomento whereArgs:                     tamente per il metodo execSQL() descritto al
                                                                   paragrafo precedente.
SQLiteDatabase	db	=	mioDatabaseHelper.getWritable                  Ad esempio la tabella “agenda” potrebbe essere
                                                   Database();     cancellata semplicemente chiamando:
ContentValues	values	=	new	ContentValues();
values.put(“telefono”,	“068390239”);                                SQLiteDatabase	db	=	mioDatabaseHelper.getWritable
String	whereClause	=	“nome	=	‘Mario’	AND	                                                                        Database();
                                            cognome	=	‘Rossi’”;     db.execSQL(“DROP	TABLE	agenda”);




    64
h ttp :/ / www. i o p r o g r a m m o. it                                                                                       2010 / 57
                                                                                                                      Settembre And roi d pr o g r am m in g
                                  MOBILE               Android: l’accesso al
                                                    Android: l’accesso al DB DB                         Android programming


                                   il metodo Query                                               String orderBy = “_id ASC”;

                                   Le operazioni di lettura e ricerca vanno svolte               db.query(“agenda”, columns, selection, selectionArgs,

                                   servendosi di uno dei metodi query() messi a                                                          null, null, orderBy);

                                   disposizione dagli oggetti SQLiteDatabase. Il
                                   principale di questi è:                                       Se preferite esprimere le vostre ricerche in SQL puro,
                                                                                                 anziché usare il metodo di convenienza query(),
                                   public Cursor query(String table, String[] columns,           potete usare direttamente il metodo rawQuery():
                                              String selection, String[] selectionArgs, String
                                                     groupBy, String having, String orderBy)     String query = “SELECT _id FROM agenda WHERE
                                                                                                                       cognome = ? ORDER BY _id ASC”;

                                   Analizziamo insieme i tanti argomenti richiesti:              String[] selectionArgs = { “Rossi” };
                                                                                                 db.rawQuery(query, selectionArgs);

                                   •	 table è il nome della tabella da interrogare.
                                   •	 columns è la lista con i nomi delle colonne i cui          Questa query è equivalente alla precedente, ma
                                   •	 valori devono essere inclusi nella risposta. Se null       espressa completamente in SQL. L’SQL puro
                                   •	 vengono restituite tutte le colonne della tabella.         torna utile soprattutto nei casi in cui si devono
                                   •	 selection è la clausola WHERE, come nei casi del           costruire delle query complesse, magari con
                                   •	 paragrafo precedente. Se null vengono restituite           relazioni tra più tabelle.
                                   •	 tutte le righe della tabella.                              Qualunque sia il metodo di interrogazione
                                   •	 selectionArgs è la lista degli argomenti della clau        utilizzato, il risultato sarà sempre un oggetto
                                     sola WHERE al punto precedente.                             di classe android.database.Cursor. La forma di
                                   •	 groupBy è la clausola SQL di raggruppamento. Se            codice corretta, quindi, è del tipo:
                                   •	 null non si applica alcun raggruppamento.
                                   •	 having è la clausola SQL di restrizione sul rag-           Cursor cursor = dq.query(…);

                                      gruppamento. Se null non si applicano restrizioni
                                      al raggruppamento.                                         oppure:
                                   •	 orderBy è la clausola SQL di raggruppamento. Se
                                      null non si applica un ordinamento specifico alla          Cursor cursor = db.rawQuery(…);

                                      lista dei risultati restituiti.
                                                                                                 I cursori sono gli oggetti di Android che per-
               NOTA                Come è possibile osservare, se si mastica un                  mettono di navigare all’interno di un result set,
                                   po’ di SQL, il metodo query() non fa altro                    ossia nell’insieme dei risultati restituiti da una
          SQLiteQuery              che richiedere in argomento le singole parti                  query. Dovete pensare ai risultati di una query
              BuiLder              che costituiscono la classica istruzione SQL di               come ad una tabella di natura temporanea,
         La classe android.        SELECT, del tipo:                                             organizzata in righe e colonne.
            database.sqlite.                                                                     Le colonne sono quelle selezionate dalla vostra
 SQLiteQueryBuilder è una          SELECT … FROM … WHERE … GROUP BY … HAVING …                   istruzione di ricerca, mentre le righe conten-
   classe di utilità che può                                                      ORDER BY …
 essere utilizzata per com-                                                                      gono i dati di ciascun risultato individuato. Il
   porre query di maggiore                                                                       cursore è un meccanismo che di volta in volta
   complessità, in maniera         Ad eccezione del nome della tabella da inter-                 indica una riga diversa di questa tabella tem-
   strutturata, senza dover        rogare, tutti gli altri argomenti possono essere              poranea. Il cursore può dirvi anzitutto quante
       scrivere codice SQL.        nulli. In pratica chiamare:                                   righe ci sono:

                                   db.query(“agenda”, null, null, null, null, null, null);       int count = cursor.getCount();


                                   è come fare:                                                  Appena creato, un cursore non “punta” ad
                                                                                                 alcuna riga dei risultati. Si può farlo puntare ad
                                   SELECT * FROM agenda                                          una riga usando i suoi metodi di tipo move. Il
                                                                                                 più importante è:
                                   Immaginiamo adesso di voler ricercare gli ID
                                   di tutti i “Rossi” in agenda, ordinati in maniera             public boolean moveToNext()

                                   crescente. Dovremmo fare:
                                                                                                 Se si richiama il metodo non appena il cursore
                                   SQLiteDatabase db = mioDatabaseHelper.getReadable             è stato creato, si otterrà che il cursore punterà
                                                                                   Database();   alla prima riga del result set.
                                   String[] columns = { “_id” };                                 Chiamandolo di nuovo, il cursore si sposterà
                                   String selection = “cognome = ?”;                             sulla seconda riga, poi sulla terza, sulla quarta
                                   String[] selectionArgs = { “Rossi” };                         e così via. Il metodo restituisce true finché ci


        58 / Settembre 2010
A n d ro id p r o g r a m m ing                                                                                                                         65
                                                                                                                             h ttp ://www.io pr o g r a m m o .i t
                         Android programming          Android: l’accesso al DB DB
                                                         Android: l’accesso al                           MOBILE


sono record disponibili. Nel momento in cui si          SQLiteDatabase	db	=	mioDatabaseHelper.getReadable

è sull’ultima riga della tabella dei risultati e si                                                  Database();

invoca nuovamente moveToNext(), il metodo               String[]	columns	=	{	“_id”,	“nome”,	“cognome”	};

ritornerà false per indicare che non ci sono            String	orderBy	=	“_id	ASC”;

ulteriori risultati su cui muoversi. Attraverso         Cursor	cursor	=	db.query(“agenda”,	columns,	null,	null,	

questo metodo è possibile costruire un ciclo            null,	null,	orderBy);

di analisi dei risultati di una query basato sul        while	(cursor.moveToNext())	{

seguente modello:                                       	 long	id	=	cursor.getLong(0);
                                                        	 String	nome	=	cursor.getString(1);
Cursor	cursor	=	db.query(…);                            	 String	cognome	=	cursor.getString(2);
while	(cursor.moveToNext())	{                           }
    // analizza la riga corrente
}                                                      Particolare attenzione deve essere prestata ai campi che
                                                       potrebbero essere nulli. Si può controllare se il valore in
La classe Cursor mette poi a disposizione altri        una colonna è nullo adoperando il seguente metodo:
metodi di tipo move, che permettono ulteriori
tipi di movimento all’interno del result set:           public	boolean	isNull(int	columnIndex)


•	 public boolean moveToFirst()                        Ad esempio:
   Porta alla prima riga del result set.
                                                        if	(cursor.isNull(1))	{

•	 public boolean moveToLast()                              // campo nullo

   Porta all’ultima riga del result set.                } else {
                                                            // campo non nullo

•	 public boolean moveToPrevious()                      		int	c	=	cursor.getInt(1);

   Si muove indietro di una riga.                       		…
                                                        }

•	 public boolean moveToPosition(int position)
   Si muove ad una riga specifica del result set.      La classe Cursor dispone poi di numerosi altri meto-
                                                       di, che permettono di esplorare più nel dettaglio il
Anche questi quattro metodi restituiscono un           result set restituito da una query. La documenta-                         L’AUTORE
booleano, per indicare se l’operazione di spo-         zione ufficiale, come sempre, è un ottimo punto di
stamento è riuscita oppure no.                         partenza per l’approfondimento.                               Carlo Pelliccia lavora
Una volta che si è puntata la riga che si intende                                                                    presso 4IT (www.4it.it),
analizzare, bisogna estrarre da questa i valori                                                                      dove si occupa di analisi
presenti per ciascuna colonna.                                                                                       e sviluppo software per
È possibile farlo con uno dei seguenti metodi:         un notepad                                                    piattaforme Java. Nella
                                                       con databaSe                                                  sua carriera di technical
•	public	byte[]	getBlob(int	columnIndex)               Per approfondire e mettere in pratica l’argomento             writer ha pubblicato cinque
•	public	double	getDouble(int	columnIndex)             database, nel CD-Rom allegato alla rivista troverete          manuali ed oltre duecento
•	public	float	getFloat(int	columnIndex)               il codice sorgente di una rivisitazione del blocco            articoli, molti dei quali
•	public	int	getInt(int	columnIndex)                   note realizzato il mese scorso, che era basato su file        proprio tra le pagine di
•	public	long	getLong(int	columnIndex)                 di testo. Questa volta il notepad gestisce i propri           ioProgrammo. Il suo sito,
•	public	short	getShort(int	columnIndex)               contenuti utilizzando un database di SQLite.                  che ospita anche diversi
•	public	String	getString(int	columnIndex)                                                                           progetti Java Open Source,
                                                                                                  Carlo Pelliccia    è disponibile all’indirizzo
I metodi di questo gruppo funzionano tutti                                                                           www.sauronsoftware.it
alla stessa maniera: restituiscono il valore della
colonna con l’indice indicato. Gli indici par-
tono da zero. Significa che se avete richiesto
le colonne “_id”, “nome”, “cognome” allora 0
corrisponde a “_id”, 1 a “nome” e 2 a “cogno-
me”. A seconda della natura del dato che si sta
estraendo dovrete scegliere il metodo più adatto
dall’elenco.
Ad esempio “nome” e “cognome” vanno recupe-
rati con getString(), mentre l’ID è un intero che      Fig.1: L’esempio presente nel CD-Rom è un blocco note che
può essere recuperato con getInt() o getLong():        salva i contenuti su database.



    66
h ttp :/ / www. i o p r o g r a m m o. it                                                                          2010 / 59
                                                                                                         Settembre And roi d pr o g r am m in g
                                                        Condividere dati in
                                          MOBILE Condividere i dati in iAndroid Android Android programming




GESTIONE DEI
CONTENT PROVIDER
I CONTENT PROVIDER COSTITUISCONO LA MANIERA DI ANDROID PER CONDIVIDERE DATI
FRA LE APPLICAZIONI. IN QUESTO ARTICOLO IMPAREREMO A CONSULTARE I PROVIDER
PREDEFINITI E VEDREMO ANCHE COME COSTRUIRE UN FORNITORE DI CONTENUTI CUSTOM




                                           N
                                                    ei due numeri precedenti abbiamo imparato          quella che fa da ponte per l’accesso al provider dei
                                                    ad interagire con il le system ed il DBMS.         contatti in rubrica. Al suo interno c’è la costante statica
                                                    Come abbiamo visto, secondo i meccanismi           CONTENT_URI, di tipo android.net.Uri, che riporta
                                           di gestione della sicurezza di Android, sia i le che        l’URI che identi ca univocamente il provider.
                                           i database sono solitamente di esclusiva proprietà          Una volta che si conosce l’URI di una tipologia di
                                           dell’applicazione che li genera. Come fare, allora,         contenuto, interagire con il provider che la eroga è
                                           per condividere dati strutturati tra più applicazioni       più o meno come fare delle interrogazioni ad un data-
                                           Android? La risposta è: mediante i Content Provider.        base. Per prima cosa si deve recuperare un’istanza
  ❑ CD ❑ WEB                               Un Content Provider è una parte di un’applicazione          dell’oggetto android.content.ContentResolver. Stando
  AndroidCP.rar                            Android che si occupa di rendere disponibili dei dati       all’interno di una Activity (o avendo a disposizione un
                                           alle altre applicazioni installate nel sistema. Ogni        oggetto android.app.Context) si può usare il metodo
                   cdrom.ioprogrammo.it
                                           applicazione, pertanto, può de nire una o più tipolo-       getContentResolver(). Ad esempio:
                                           gie di dati e rendere poi disponibili tali informazioni
                                           esponendo uno o più Content Provider. Nell’ordine           ContentResolver cr = getContentResolver();

                                           inverso, invece, qualunque applicazione può richie-
                                           dere l’accesso ad un particolare tipo di dato: il sistema   Gli oggetti ContentResolver permettono le interroga-
                                           la metterà in contatto con il corrispondente Content        zioni attraverso il loro metodo:
                                           Provider precedentemente installato nel sistema.
                                                                                                       public Cursor query(Uri uri, String[] projection, String
                                                                                                               selection, String[] selectionArgs, String sortOrder)


                                           RICERCA DEI CONTENUTI                                       I parametri da fornire sono i seguenti:
                                           Ogni tipo di contenuto esposto mediante Content
                                           Provider viene identi cato attraverso un URI, cioè un       • uri è l’indirizzo che identi      ca il tipo di contenuto
                                           indirizzo univoco. La forma tipica di questo genere di          ricercato.
                                           URI è:                                                      •   projection è la lista con i nomi delle colonne i cui
                                                                                                           valori devono essere inclusi nella risposta. Se null,
                                            content://riferimento-di-base/bla/bla/bla                      vengono restituite tutte le colonne disponibili.
                                                                                                       •   selection è la clausola WHERE. Se null, vengono
                  REQUISITI                Android dispone di diversi Content Provider built-in,           restituite tutte le righe disponibili.
                                           come quello per le immagini o quello per accedere ai        •   selectionArgs è la lista degli argomenti della clau-
 Conoscenze richieste                      contatti in rubrica. L’URI per accedere ai contatti, ad         sola WHERE al punto precedente.
     Basi di Java                          esempio, è:                                                 •   sortOrder è la clausola SQL di ordinamento. Se
                                                                                                           null, non si applica un ordinamento speci co alla
 Software                                   content://com.android.contacts/contacts                        lista dei risultati restituiti.
     Java SDK (JDK) 5+,
     Android SDK, Eclipse
     3.3+, ADT
                                           Siccome questi URI sono un po’ arbitrari, per con-          Questo schema, come è possibile notare, ricalca molto
 Impegno
                                           venienza si è soliti fare in modo che qualche classe        da vicino quello conosciuto il mese scorso, quando
                                           riporti l’indirizzo in maniera statica, in modo che non     abbiamo preso in esame i metodi per la ricerca in un
                                           sia necessario digitarlo per esteso. I Content Provider     database. Anche il tipo del risultato restituito è di tipo
 Tempo di realizzazione                    preinstallati in Android sono consultabili al package       a noi noto: si tratta di un oggetto android.database.
                                           android.provider. In questo pacchetto, ad esempio,          Cursor, che possiamo sfogliare per sondare i record
                                           si trova la classe ContactsContract.Contacts, che è         restituiti come risposta alla nostra query. Si faccia


        60 / Ottobre 2010
A n d ro id p r o g r a m m ing                                                                                                                                  67
                                                                                                                                     h ttp ://www.io p r o g r a m m o .i t
                         Android programming Condividere i dati ini AndroidAndroid MOBILE
                                                    Condividere dati in


solamente attenzione al fatto che il cursore restituito,                        public void onCreate(Bundle savedInstanceState) {

in questo caso, potrebbe anche essere nullo: avviene                                super.onCreate(savedInstanceState);

quando l’URI fornito al metodo non corrisponde ad                                   Uri uri = Contacts.CONTENT_URI;

alcun provider registrato nel sistema.                                              String[] projection = { Contacts._ID, Contacts.

Per comporre query complesse, così come per pren-                                                                       DISPLAY_NAME };

dere in esame i risultati restituiti, è necessario cono-                            String selection = null;

scere il nome ed il tipo delle colonne che costituiscono                            String[] selectionArgs = null;

lo specifico tipo di dato richiesto. Anche in questo caso                           String sortOrder = Contacts.DISPLAY_NAME + “

si è soliti includere tali informazioni all’interno delle                                                                           ASC”;

costanti statiche di una classe. Nel caso della rubrica                             Cursor cursor = managedQuery(uri, projection,

di sistema, ad esempio, le colonne disponibili sono                                                  selection, selectionArgs, sortOrder);                 NOTA
elencate all’interno ContactsContract.Contacts. Ecco                                setListAdapter(new CursorAdapter(this, cursor, true)

un esempio di codice che interroga la lista dei contatti                                                                                {      è permesso?
di Android, ordinando i risultati in base al loro nome                                @Override                                                Il modello di sicurezza di
visualizzato:                                                                         public View newView(Context context, Cursor              Android fa sì che le appli-
                                                                                                               cursor, ViewGroup parent) {     cazioni non possano com-
ContentResolver cr = getContentResolver();                                                String displayName = cursor.getString(1);            piere determinate azioni
                                                                                                                                               senza ottenere prima un
Uri uri = Contacts.CONTENT_URI;                                                           TextView textView = new TextView(context);
                                                                                                                                               permesso specifico. Ad
String[] projection = { Contacts.DISPLAY_NAME };                                          textView.setText(displayName);                       esempio, una qualsiasi
String selection = null;                                                                  return textView;                                     applicazione non può
String[] selectionArgs = null;                                                        }                                                        connettersi alla Rete all’in-
String sortOrder = Contacts.DISPLAY_NAME + “ ASC”;                                    @Override                                                saputa dell’utente, così
                                                                                                                                               come non può manipolare
Cursor cursor = cr.query(uri, projection, selection,                                  public void bindView(View view, Context context,
                                                                                                                                               la lista dei contatti in
                                             selectionArgs, sortOrder);                                                   Cursor cursor) {     rubrica. Le applicazioni che
while (cursor.moveToNext()) {                                                             String displayName = cursor.getString(1);            vogliono compiere questo
    String displayName = cursor.getString(0);                                             TextView textView = (TextView) view;                 genere di attività devono
    Log.i(“Test”, displayName);                                                           textView.setText(displayName);                       dichiararlo esplicitamente.
                                                                                                                                               L’utente, quando installa
}                                                                                     }
                                                                                                                                               l’applicazione, viene così
cursor.close();                                                                     });                                                        informato di quali sono le
                                                                                }                                                              operazioni potenzialmente
Attenzione a gestire sempre correttamente il ciclo di                                                                                          pericolose che il software
                                                                            }                                                                  può eseguire, ed è così
vita del cursore, senza dimenticarsi di chiuderlo ad                                                                                           libero di accordare o meno
utilizzo completato. Se si lavora all’interno di una atti-                                                                                     la propria fiducia al produt-
vità, risulta conveniente sostituire il metodo query()                     Si faccia attenzione al fatto che questa attività, per gira-        tore dell’app.
di ContentResolver con l’analogo managedQuery() di                         re senza incappare in errori, necessita del permesso                Dal punto di vista dello
Activity: in questo caso, infatti, la gestione del cursore                 android.permission.READ_CONTACTS (per i dettagli,                   sviluppo, un permesso può
viene svolta automaticamente dall’attività.                                fate riferimento al box qui accanto).                               essere richiesto aggiun-
                                                                                                                                               gendo nell’AndroidMani-
Per esercizio su quanto appena appreso, realizziamo                                                                                            fest.xml dell’applicazione
ora una semplice attività capace di mostrare in una                                                                                            un tag del tipo:
lista il nome di ogni contatto presente in rubrica:                                                                                            <uses-permissionandroid:
                                                                                                                                               name=”permesso_richie-
package it.ioprogrammo.contentproviderdemo01;                                                                                                  sto” />
                                                                                                                                               L’elenco dei permessi a
                                                                                                                                               disposizione è flessibile
import android.app.ListActivity;
                                                                                                                                               ed espandibile. La docu-
import android.content.Context;                                                                                                                mentazione ufficiale riporta
import android.database.Cursor;                                                                                                                i permessi built-in in
import android.net.Uri;                                                    Fig.1: Questa attività si collega al Content Provider della         Android. Usando un editor
                                                                           rubrica, riuscendo così a mostrare tutti i contatti registrati      avanzato, come Eclipse,
import android.os.Bundle;
                                                                           nel telefono                                                        è poi possibile ottenere
import android.provider.ContactsContract.Contacts;
                                                                                                                                               una lista visuale di tutti i
import android.view.View;                                                                                                                      permessi disponibili nel
import android.view.ViewGroup;                                                                                                                 sistema per cui si sta svi-
import android.widget.CursorAdapter;                                                                                                           luppando.
import android.widget.TextView;

                                                                           NoN solo ricerche
public class ContentProviderDemo01Activity extends                         I Content Provider sono in grado di fornire anche
                                                          ListActivity {   funzionalità di inserimento, aggiornamento e cancel-
                                                                           lazione dei record. La classe ContentResolver, oltre al
    @Override                                                              già esaminato metodo query(), mette a disposizione i



    68
h ttp :/ / w ww. i o p r o g r a m m o. it                                                                                                      2010 / 61
                                                                                                                                       Ottobre And roi d pr o g r am m in g
                                                   Condividere dati in
                                     MOBILE Condividere i dati ini AndroidAndroid Android programming


                                      seguenti altri metodi:                                         storage esterno, per ottenerne l’elenco.
                                                                                                  2. Mostrare le immagini, facendo uso di un widget
                                      •	 public	Uri	insert(Uri	uri,	ContentValues	values)            android.widget.Gallery (cfr. ioProgrammo 151).
                                        Inserisce un nuovo record del tipo specificato            3. Al clic su una delle immagini, eseguire la can-
                                        mediante il parametro uri. I valori per i campi              cellazione della medesima, previa conferma da
                                        del nuovo record devono essere specificati attra-            parte dell’utente.
                                        verso la mappa values, di tipo android.content.
                                        ContentValues. Il metodo restituisce l’URI di detta-      Tradotto in codice:
                                        glio assegnato all’elemento appena inserito.
                                                                                                  package it.ioprogrammo.contentproviderdemo02;
               NOTA                   •	 public	 int	 update(Uri	 uri,	 ContentValues	            ...

                                        values,	String	where,	String[]	selectionArgs)             public class ContentProviderDemo02Activity extends

     ricerca per iD                     Aggiorna uno o più record del tipo specificato            Activity {

    Tutti i contenuti esposti           mediante il parametro uri. La selezione avviene           	 private	static	final	int	DELETE_DIALOG	=	1;
mediante provider dovreb-               attraverso l’uso combinato dei parametri where                  private Gallery gallery = null;
    bero avere una colonna              e selectionArgs. I nuovi valori da assegnare ai                 private int selectedImageId;
  chiamata _ID, con l’iden-
      tificativo numerico del           record selezionati devono essere specificati attra-
                                        verso la mappa values, di tipo android.content.                 @Override
  record, univoco nella sua
   categoria. Se si conosce             ContentValues. Il metodo restituisce il numero dei              public void onCreate(Bundle savedInstanceState) {
     l’ID di un record e lo si          record aggiornati.                                                super.onCreate(savedInstanceState);
       vuole estrarre diretta-                                                                            gallery = new Gallery(this);
    mente dal suo provider,
      si può fare ricorso alla        •	 public	int	delete(Uri	uri,	String	where,	String[]	               Uri uri = MediaStore.Images.Media.EXTERNAL_

                                        selectionArgs)                                                                                             CONTENT_URI;
    classe android.content.
ContentUris e al suo meto-              Cancella uno o più record del tipo specificato                  ...
   do statico withAppende-              mediante il parametro uri. La selezione avviene
dId(): Uri uri = ContentUris.           attraverso l’uso combinato dei parametri where e
    withAppendedId(uri_di_
        base_del_contenuto,             selectionArgs. Il metodo restituisce il numero dei
           id_del_contenuto);           record cancellati.                                        creare uN coNteNt
    Cursor c = cr.query(uri,                                                                      Provider
          null, null, null, null);    Implementiamo un esempio pratico. Questa volta              Se volete condividere i dati della vostra applicazio-
                                      lavoreremo con la lista delle immagini memorizzate          ne con gli altri software installati nel telefono, pote-
                                      nella galleria del telefono. L’URI di base per l’accesso    te implementare il vostro Content Provider. Farlo è
                                      alle immagini che sono nello storage esterno viene          molto semplice: bisogna estendere la classe android.
                                      riportato nella proprietà:                                  content.ContentProvider, che richiede l’implementa-
                                                                                                  zione dei seguenti metodi:
                                       android.provider.MediaStore.Images.Media.EXTERNAL_
                                                                                CONTENT_URI       •	 public	boolean	onCreate()
                                                                                                     Il codice da eseguirsi alla creazione del provider.
                                      Tutte le immagini recuperate mediante l’apposito               Il metodo deve restituire un booleano: true, per
                                      provider dispongono di una colonna “_ID”, in cui               segnalare che la creazione del provider è andata a
                                      viene riportato il loro identificativo numerico univoco.       buon fine; false, in caso contrario.
                                      Come indicato nel box laterale, dato l’ID di un conte-      •	 public	String	getType(Uri	uri)
                                      nuto, è possibile avere un suo URI specifico facendo:          Dato un URI di gestione del provider, questo meto-
                                                                                                     do deve restituire il tipo MIME del contenuto cor-
                                       Uri uri = ContentUris.withAppendedId(uri_generico, id);       rispondente. Solitamente, con tipi di dati perso-
                                                                                                     nalizzati, non bisogna far altro che inventare il
                                      Dato l’URI puntuale di un contenuto-immagine, è                nome della tipologia, seguendo però alcuni criteri.
                                      possibile caricare l’immagine (sotto forma di oggetto          Se l’URI specificato corrisponde ad un contenuto
                                      android.graphics.Bitmap) facendo:                              specifico (in genere avviene quando l’URI contiene
                                                                                                     l’ID del contenuto), allora bisogna restituire un tipo
                                       ContentResolver cr = new ContentResolver(this);               MIME del tipo:
                                       Bitmap image = MediaStore.Images.Media.getBitmap(cr,
                                                                                          uri);   vnd.android.cursor.item/vnd.il_nome_del_tipo


                                      Sfruttando queste conoscenze, andiamo a realizzare          Per gli URI che corrispondono a gruppi di contenuti
                                      un’attività in grado di svolgere i seguenti compiti:        (senza ID, quindi), la formula è del tipo:

                                      1. Interrogare il Content Provider delle immagini su        vnd.android.cursor.dir/vnd.il_nome_del_tipo




        62 / Ottobre 2010
A n d ro id p r o g r a m m ing                                                                                                                               69
                                                                                                                                  h ttp ://www.io p r o g r a m m o .i t
                         Android programming Condividere i dati ini AndroidAndroid MOBILE
                                                    Condividere dati in


•	 public	 Cursor	 query(Uri	 uri,	 String[]	 projec-         authorities, invece, definisce la parte fondamen-
   tion,	 String	 selection,	 String[]	 selectionArgs,	       tale dell’URI gestito dal provider, cioè quello che
   String	sortOrder)                                          dovranno utilizzare le altre applicazioni per inte-
   Il metodo richiamato per eseguire una ricerca tra i        ragire con il nostro Content Provider. Ad esempio,
   dati gestiti dal provider.                                 facciamo il caso che autorities sia:

•	 public	insert(Uri	uri,	ContentValues	values)               it.ioprogrammo.arretrati

   Il metodo richiamato per eseguire un inserimento
   nei dati gestiti dal provider.                             In questo caso, il Content Provider riceverà tutte le
                                                              richieste il cui URI sia del tipo:
•	 public	   int	 update(Uri	 uri,	 ContentValues	
   values,	String	selection,	String[]	selectionArgs)          content:// it.ioprogrammo.arretrati/bla/bla/bla

   Il metodo richiamato per eseguire un aggiornamen-
   to dei dati gestiti dal provider.                          Per concludere, è poi necessario comunicare a chi                             NOTA
                                                              dovrà utilizzare il provider quale sia il suo URI di
•	 public	   int	 delete(Uri	 uri,	 String	 selection,	       base e quali i nomi ed i tipi delle colonne di ciascun            la classe
   String[]	selectionArgs)                                    tipo di contenuto gestito. Solitamente conviene                   Urimatcher
   Il metodo richiamato per eseguire una cancellazio-         realizzare una o più classi che contengano queste                 Uno strumento molto utile
   ne fra i dati gestiti dal provider.                        informazioni, da rendere poi disponibili a chi dovrà              quando si costruiscono dei
                                                              servirsi del provider.                                            Content Provider complessi
Una volta che il Content Provider è stato implemen-           Proviamo un esempio. Recuperiamo il progetto                      è la classe android.
tato, bisogna registrarlo nel file AndroidManifest.xml,       del blocco note realizzato nel numero precedente                  content.UriMatcher.
osservando il seguente modello:                               e andiamo ad arricchirlo con un Content Provider,                 Questa utilità permette di
                                                              capace di esportare verso l’esterno le note gestite               lavorare più agilmente con
<?xml version=”1.0” encoding=”utf-8”?>                        dall’applicazione:                                                gli oggetti Uri di Android,
<manifest ...>                                                                                                                  discriminando facilmente
  <application ...>                                           package it.ioprogrammo.notepad;                                   l’area di appartenenza di
     <provider android:name=”MioContentProvider”              ...                                                               ciascun indirizzo ricevuto
      android:authorities=”mio_dominio/mio_tipo_di_           public class NotePadContentProvider extends                       da un provider di contenuti.
                                                   dato” />                                            ContentProvider {
  </application>                                              ...
</manifest>

                                                              Registriamo il provider nel file AndroidManifest.xml
L’attributo name serve per specificare il nome                dell’applicazione:
della classe che implementa il provider; l’attributo
                                                              <provider android:name=”NotePadContentProvider”
                                                                          android:authorities=”it.ioprogrammo.notepad” />                    L’AUTORE

                                                              Aggiornate ora l’applicazione sul vostro smartpho-                Carlo Pelliccia lavora
                                                              ne o nell’emulatore. Da questo momento in poi                     presso 4IT (www.4it.it),
                                                              l’elenco delle note è gestibile non solo attraverso               dove si occupa di analisi
                                                                                                                                e sviluppo software per
                                                              l’attività incorporata dall’applicazione stessa, ma               piattaforme Java. Nella
                                                              anche attraverso il Content Provider che risponde a               sua carriera di technical
                                                              partire dall’URI:                                                 writer ha pubblicato cinque
                                                                                                                                manuali ed oltre duecento
                                                              content://it.ioprogrammo.notepad                                  articoli, molti dei quali
                                                                                                                                proprio tra le pagine di
                                                                                                                                ioProgrammo. Il suo sito,
                                                              Per provare, implementate una nuova applicazione                  che ospita anche diversi
                                                              Android, estranea alla precedente, al cui interno va              progetti Java Open Source,
                                                              inserita la seguente attività:                                    è disponibile all’indirizzo
                                                                                                                                www.sauronsoftware.it
                                                              package it.ioprogrammo.notepadclient;
                                                              ...
                                                              public class NotePadClientActivity extends ListActivity
                                                                    {
                                                                    ...
Fig.2: Le note generate dall’applicazione del mese scorso
vengono ora consultate attraverso una seconda applicazio-
ne, passando per un Content Provider                                                                       Carlo Pelliccia



   70
h ttp :/ / www. i o p r o g r a m m o. it                                                                                       2010 / 63
                                                                                                                        Ottobre And roi d pr o g r am m in g
                                                       con i servizi con i servizi Android
                                           MultitaskingMultitasking Android
                                         MOBILE                                        Android programming




LE APPLICAZIONI
GIRANO IN PARALLELO
I SERVIZI SONO QUELLA FUNZIONALITÀ DI ANDROID CHE PERMETTE DI ESEGUIRE
OPERAZIONI IN SOTTOFONDO, ANCHE QUANDO L’APPLICAZIONE CHE LE HA AVVIATE
NON È PIÙ ATTIVA. INSOMMA: MULTITASKING ALLO STATO PURO, ANCHE IN MOBILITÀ!




                                          N
                                                   ella prima puntata di questo corso (appar-          mediale possa essere rimossa dallo schermo. Lo si può
                                                   sa su ioProgrammo 143) si è subito spiega-          fare, naturalmente, con un servizio.
                                                   to come le applicazioni Android contenga-           Ecco un altro esempio, per chiarire ancora meglio il
                                          no sempre uno o più componenti scelti fra i quattro          concetto: immaginiamo di dover realizzare un’appli-
                                          tipi fondamentali: le attività, i servizi, i broadcast       cazione che, di tanto in tanto, si colleghi ad Internet per
                                          receiver e i content provider. Delle attività ci siamo       scaricare via Web delle notizie. L’utente ha imposto un
                                          occupati a lungo, e continueremo a farlo in futuro.          filtro sulle notizie di suo interesse, specificando delle
                                          Nel numero precedente, invece, sono stati intro-             parole chiave: solo le news che contengono le keyword
 ❑ CD ❑ WEB                               dotti i content provider, oggetti indispensabili per         specificate gli devono essere notificate. È possibile farlo
 Android14.rar                            la condivisione dei dati fra più applicazioni. Oggi ci       avviando un servizio che, in sottofondo, si colleghi alla
                                          occuperemo dei servizi.                                      rete e analizzi le notizie di volta in volta disponibili.
                  cdrom.ioprogrammo.it
                                                                                                       Quando si incontra una notizia in grado di soddisfare
                                                                                                       il filtro impostato, il servizio non deve far altro che lan-
                                                                                                       ciare un’attività per notificare l’evento all’utente. Con i
                                          COS’È UN SERVIZIO                                            servizi di Android è possibile fare anche questo.
                                          Un servizio, nel gergo di Android, è una parte di una
                                          applicazione che gira in background. A differenza
                                          delle attività, i servizi non dispongono di un’interfaccia
                                          grafica attraverso la quale interagire con l’utente. Allo    CREARE UN SERVIZIO
                                          stesso tempo, però, i servizi non vanno confusi né con       La prima cosa da farsi per realizzare un servizio è
                                          i processi né con i thread, che sono cose distinte e ben     estendere la classe android.app.Service:
                                          diverse. Un servizio, infatti, è gestito direttamente da
                                          Android, e per questo possiede un proprio peculiare          import android.app.Service;

                                          ciclo di vita. In più i servizi si avvantaggiano delle       public class MioServizio extends Service {

                                          interfacce di programmazione messe a disposizione da             // ...

                                          Android, attraverso le quali possono integrarsi profon-      }

                                          damente con il sistema sottostante.
                                          Un servizio è necessario ogni volta che un’applicazione      La classe Service richiede l’implementazione del
                                          deve fare qualcosa in background, senza occupare lo          metodo astratto onBind(). Si tratta di un metodo
                 REQUISITI                schermo. Si pensi, ad esempio, ad un’applicazione tipo       necessario quando il servizio che si sta realizzando
                                          un multimedia player, in grado di riprodurre album           dovrà essere reso pubblico. Altre applicazioni installa-
Conoscenze richieste                      musicali in formato MP3. Un software di questo tipo          te nel sistema, in questo caso, potranno collegarsi con
    Basi di Java                          disporrà sicuramente di una o più attività per intera-       il servizio (operazione definita, per l’appunto, bind) e
                                          gire con l’utente, in modo che sia possibile selezionare     interagire con esso. Android comprende alcuni servizi
Software
                                          un album musicale ed avviarne la riproduzione. Una           che offrono questa caratteristica, come ad esempio
    Java SDK (JDK) 5+,
    Android SDK, Eclipse                  volta che l’esecuzione ha avuto inizio, però, non è          quello utile per acquisire le coordinate geografiche dal
    3.3+, ADT
                                          buona cosa che l’attività del player rimanga sempre e        ricevitore GPS.
Impegno
                                          costantemente sul display dello smartphone. L’utente,        Se non interessa sviluppare un servizio in grado di
                                          ad esempio, potrebbe voler navigare in Internet, gio-        interagire in maniera avanzata con le applicazioni
                                          care o fare altro ancora, senza però interrompere            esterne, come nei casi più semplici, la cosa migliore da
Tempo di realizzazione                    l’ascolto. Ecco allora che è conveniente fare in modo        fare è implementare onBind() alla seguente maniera:
                                          che l’esecuzione della playlist avvenga in sottofondo,
                                          in modo che l’attività di interfaccia del player multi-      import android.content.Intent;




        60 / Novembre 2010
A n d ro id p r o g r a m m ing                                                                                                                                  71
                                                                                                                                     h ttp ://www.io pr o g r a m m o .i t
                                                     con i servizi con i servizi Android
                                         MultitaskingMultitasking Android
                         Android programming                                         MOBILE


import android.os.IBinder;                               CICLO DI VITA
// ...                                                   DI UN SERVIZIO
@Override                                                Ora che siamo in grado di creare l’ossatura di un
public IBinder onBind(Intent intent) {                   servizio e di gestire l’avvio e l’arresto dello stesso,
     return null;                                        andiamo a imparare come inserire al suo interno
}                                                        la nostra logica di programmazione, che il servizio
                                                         dovrà poi eseguire in sottofondo. La prima cosa da
Il passo successivo consiste nel registrare il nuovo     comprendere è il ciclo di vita dei servizi Android,
servizio nel file AndroidManifest.xml:                   che tra l’altro è molto semplice e lineare, perlomeno
                                                         fino a quando il servizio è usato a livello elementare.
<?xml version=”1.0” encoding=”utf-8”?>                   Quando il servizio viene creato ed avviato, il sistema
<manifest ...>                                           chiama automaticamente il suo metodo:
    <application ...>
     <service android:name=”MioServizio” />              public	void	onCreate()                                                   NOTA
    </application>
</manifest>                                              La chiusura di un servizio, invece, viene gestita
                                                         mediante il metodo:                                         ONLOWMEMORY()
Lo scheletro del servizio, a questo punto, è già                                                                     Se il telefono è a corto di
pronto.                                                  public	void	onDestroy()                                     memoria, il vostro servizio
                                                                                                                     riceverà una chiamata sul
                                                                                                                     metodo onLowMemory().
                                                         Un servizio può venire arrestato e distrutto in tre casi:   Potete ridefinire questo
                                                                                                                     metodo per intercettare
AVVIARE ED ARRESTARE                                     1. Quando, come abbiamo visto in precedenza, un             l’evento e cercare così di
UN SERVIZIO                                              altro componente della stessa applicazione chiama           collaborare con il sistema
I servizi, per entrare in funzione, devono essere        stopService().                                              che ospita la vostra appli-
                                                                                                                     cazione. Se il servizio, ad
avviati. È possibile avviare un servizio dall’inter-     2. Un servizio può arrestarsi da solo, chiamando il suo     esempio, tiene in memoria
no di un’attività, di un content provider o di un        stesso metodo stopSelf().                                   un grosso quantitativo di
altro servizio. La classe android.content.Context,       3. Come nel caso delle attività, un servizio può essere     dati, qui potreste rilasciar-
da cui derivano tutti i mattoni fondamentali della       arrestato dal sistema nel momento in cui le risorse         ne alcuni, per fare spazio
programmazione Android, mette a disposizione i           scarseggiano ed è necessario liberare il processore e       alle altre applicazioni che
                                                                                                                     ne hanno bisogno.
seguenti metodi per il controllo dei servizi:            la memoria.

•	 public	ComponentName	startService(Intent	             Naturalmente i metodi onCreate() e onDestroy() pos-
   service)		                                            sono essere ridefiniti a nostro piacimento, per fare
   Avvia il servizio specificato attraverso il parame-   in modo di intercettare gli eventi e mettere quindi in
   tro di tipo android.content.Intent. Restituisce un    moto la nostra logica.
   oggetto android.content.ComponentName che
   riporta il nome di dettaglio del servizio avviato.
•	 public	boolean	stopService(Intent	service)
   Arresta il servizio specificato attraverso il para-   UNA DIMOSTRAZIONE
   metro di tipo android.content.Intent. Restituisce     CONCRETA
   un booleano per indicare se l’operazione è riu-       Facciamo una prova con un servizio così definito:
   scita (true) o meno (false).
                                                         package it.ioprogrammo.servicedemo01;

Immaginiamo di aver implementato il servizio
contenuto nella classe MioServizio, registrato poi       import java.util.Timer;

correttamente nell’AndroidManifest.xml dell’appli-       import java.util.TimerTask;

cazione, come indicato nel paragrafo precedente.         ...

A questo punto, da un qualsiasi altro componente
della medesima applicazione, come ad esempio             Questo servizio, all’avvio, usa le classi java.util.Timer
un’attività, è possibile avviare il servizio chiamando   e java.util.TimerTask per compiere ciclicamente
semplicemente:                                           un’operazione. Ogni cinque secondi viene immessa
                                                         la scritta “Servizio in esecuzione” nel log di Android.
tartService(new Intent(this, MioServizio.class));        L’operazione si ripete fino all’arresto del servizio. In
Il servizio può poi essere arrestato chiamando ana-      più il servizio annota sul log anche i propri cambi di
logamente:                                               stato (create e destroy). Serviamoci ora di una semplice
                                                         attività per disporre dei comandi utili per avviare ed
stopService(new Intent(this, MioServizio.class));        interrompere il servizio:



    72
h ttp :/ / www. i o p r o g r a m m o. it                                                                          2010 / 61
                                                                                                          Novembre And roi d pr o g r am m in g
                                      MultitaskingMultitasking con i servizi Android
                                   MOBILE         con i servizi Android          Android programming


                                     package it.ioprogrammo.servicedemo01;                           Provate inoltre ad avviare il servizio e ad abbando-
                                     ...                                                             nare l’attività per fare altro. Vi capiterà di notare che
                                     public class ServiceDemo01Activity extends Activity {           l’attività può essere distrutta, ma il servizio resterà
                                           @Override                                                 lo stesso in esecuzione in background.
                                           public void onCreate(Bundle savedInstanceState) {
                                            super.onCreate(savedInstanceState);
                                            Button bottoneAvvia = new Button(this);
                                            bottoneAvvia.setText(“Avvia il servizio”);               WALLPAPER CHANGER
                                            bottoneAvvia.setOnClickListener(new View.                Grazie all’esempio appena esaminato siamo ora in
                                                                               OnClickListener() {   grado di programmare un reale servizio Android,
                                               @Override                                             secondo le nostre esigenze e la nostra fantasia.
               NOTA                            public void onClick(View v) {                         Sfruttiamo allora le conoscenze acquisite per realiz-
                                                   avviaServizio();                                  zare un’applicazione un po’ meno didattica ed un
          LANCIARE                             }                                                     po’ più concreta: un wallpaper changer automatico,
        UN’ATTIVITÀ                         });                                                      cioè un’applicazione che ogni tanto (ad esempio ogni
     DA UN SERVIZIO                  ...                                                             minuto) cambi automaticamente l’immagine di sfondo
   I servizi, come si è visto,                                                                       del telefono.Per cominciare, create nel vostro ambiente
       non hanno interfaccia        L’attività è molto semplice: non fa altro che disporre           di sviluppo il progetto “WallpaperChanger”. Il package
       grafica e non possono        sul display due bottoni utili, rispettivamente, per              di riferimento su cui lavoreremo è it.ioprogrammo.
   pertanto interagire diret-
        tamente con l’utente.       avviare ed arrestare il servizio realizzato al passo pre-        wallpaperchanger.
   Può però capitare che un         cedente. Anche l’attività, inoltre, logga i propri cambi
      servizio che fino ad un       di stato (create e destroy). Non resta che assemblare
certo momento ha girato in          l’applicazione attraverso il file AndroidManifest.xml:
 background abbia improv-
visamente bisogno di chie-           <?xml version=”1.0” encoding=”utf-8”?>
  dere o mostrare qualcosa
                                     <manifest xmlns:android=”http://schemas.android.com/
  all’utente. Per farlo si può
  lanciare un’attività. Tutti i                                                  apk/res/android”
servizi possono farlo, chia-               package=”it.ioprogrammo.servicedemo01”
             mando il metodo                                            android:versionCode=”1”      Fig.2: Come dimostra questo log, il ciclo di vita del servizio
                startActivity().           android:versionName=”1.0”>                                e quello dell’attività che abbiamo avviato sono separati:
                                           <application android:icon=”@drawable/icon”                l’attività può essere distrutta, ma il servizio resta lo stesso
                                                                                                     in esecuzione
                                                             android:label=”@string/app_name”>
                                            <activity android:name=”.ServiceDemo01Activity”
                                               android:label=”@string/app_name”>
                                               <intent-filter>                                       Le immagini che, a rotazione, verranno impostate
                                                   <action android:name=”android.intent.action.      come wallpaper, saranno parte del software stesso.
                                                                                         MAIN” />    Preparate quindi una serie di immagini JPEG di dimen-
                                                   <category android:name=”android.intent.           sione idonea, ed aggiungetele poi al percorso di proget-
                                                                         category.LAUNCHER” />       to assets/wallpapers. Potete dare alle immagini il nome
                                               </intent-filter>                                      che preferite. Il cuore dell’applicazione, naturalmente,
                                            </activity>                                              è un servizio:
                                            <service android:name=”MioServizio” />
                                           </application>                                            package it.ioprogrammo.wallpaperchanger;
                                     </manifest>                                                     ...
                                                                                                     public class WallpaperChangerService extends Service {

                                    Lanciate l’applicazione e monitoratene il log.                         public static boolean STARTED = false;

                                    Avviate ed arrestate il servizio quante volte volete.                  private String[] availableWallpapers;
                                                                                                           private int currentWallpaperIndex;
                                                                                                           private Timer timer;
                                                                                                     ...


                                                                                                     L’ossatura è la stessa dell’esempio precedente, con un
                                                                                                     Timer ed un TimerTask impiegati per compiere ciclica-
                                                                                                     mente l’operazione di aggiornamento del wallpaper.
                                                                                                     Le immagini disponibili vengono lette dal percorso
                                                                                                     assets/wallpaper servendosi di un android.content.res.
                                    Fig.1: La semplice GUI realizzata per avviare ed arrestare       AssetManager, che viene recuperato con il metodo
                                    il servizio di prova
                                                                                                     getAssets(). Ogni 60 secondi viene selezionata l’imma-


       62 / Novembre 2010
A n d ro id p r o g r a m m ing                                                                                                                                 73
                                                                                                                                    h ttp ://www.io pr o g r a m m o .i t
                                                     con i servizi con i servizi Android
                                        Multitasking Multitasking Android
                         Android programming                                        MOBILE


gine successiva dell’elenco letto inizialmente. L’oggetto         package it.ioprogrammo.wallpaperchanger;

android.graphics.Bitmap corrispondente al wallpaper               ...

da mostrare, viene caricato servendosi della classe di            public class WallpaperChangerActivity extends Activity

utilità android.graphics.BitmapFactory. Impostare un              {

oggetto Bitmap come wallpaper è davvero molto sem-                      private Button bStartService;

plice in Android: basta servirsi del singleton android.                 private Button bStopService;

app.WallpaperManager e del suo metodo setBitmap().                      private Button bFinish;

Infine il servizio memorizza il proprio stato nella pro-                @Override

prietà statica STARTED, che ci tornerà utile a breve. Ora               public void onCreate(Bundle savedInstanceState) {
                                                                                                                                               NOTA
che il servizio è pronto ci serve un’attività per coman-          ...

darne l’avvio e l’arresto. Facciamo le cose per bene e
serviamoci di file XML per la definizione delle stringhe          Anche in questo caso il modello utilizzato viene                 STARTFOREGROUND
e dei layout. Cominciamo con il file values/strings.xml:          dall’esempio del paragrafo precedente. Rispetto al               Chiamando il metodo
                                                                  caso precedente, qui in più si consulta lo stato del             startForeground() si può
<?xml version=”1.0” encoding=”utf-8”?>                            servizio, in modo da abilitare e disabilitare secon-             indicare che il servizio è
<resources>                                                                                                                        importante e che il sistema
                                                                  do necessità i primi due pulsanti dell’interfaccia.              dovrebbe cercare di non
    <string name=”app_name”>Sfondi automatici</string>            Inoltre questa attività può concludersi da sola grazie           distruggerlo mai, anche
    <string name=”startService”>Gestisci gli sfondi</string>      al terzo bottone inserito, il cui listener associato             in caso di necessità di
    <string name=”stopService”>Smettila di gestire gli            richiama il metodo finish() dell’attività. Per il resto,         memoria. Ciò non significa
                                                sfondi</string>   niente di nuovo.                                                 che il servizio non sarà mai
    <string name=”finish”>Nascondi</string>                                                                                        distrutto automaticamente,
                                                                                                                                   ma soltanto che la sua
</resources>
                                                                                                                                   priorità sarà innalzata e
                                                                                                                                   che si cercherà di evita-
Queste stringhe sono utilizzate nel layout da defini-                                                                              re l’evento nei limiti del
re al percorso layout/main.xml:                                                                                                    possibile. Nel caso in cui
                                                                                                                                   un servizio così impostato
                                                                                                                                   dovesse comunque esse-
<?xml version=”1.0” encoding=”utf-8”?>
                                                                                                                                   re distrutto dal sistema,
<LinearLayout xmlns:android=”http://schemas.android.                                                                               all’utente verrà mostrata
                                           com/apk/res/android”                                                                    una notifica informativa,
    android:orientation=”vertical”                                                                                                 il cui ID ed i cui conte-
    android:layout_width=”fill_parent”                                                                                             nuti vanno forniti come
                                                                                                                                   parametri del metodo
    android:layout_height=”fill_parent”>                          Fig.4: L’attività consulta lo stato del servizio per abilitare   startForeground(). In que-
    ...                                                           o disabilitare i bottoni di avvio ed arresto                     sta maniera, ad esempio,
                                                                                                                                   l’utente può essere infor-
In questo layout viene definita una semplicissima                                                                                  mato del perché il suo
                                                                                                                                   MP3 ha smesso di essere
interfaccia fatta di tre bottoni: il primo per avviare            Non resta che mettere insieme il tutto nel file                  riprodotto d’improvviso!
il servizio di cambio automatico del wallpaper,                   AndroidManifest.xml:
il secondo per arrestarlo ed il terzo per nascon-
dere l’attività che comprende l’interfaccia stessa.               <?xml version=”1.0” encoding=”utf-8”?>

Andiamo a realizzare tale attività:                               <manifest xmlns:android=”http://schemas.android.com/
                                                                                                               apk/res/android”
                                                                        package=”it.ioprogrammo.wallpaperchanger”
                                                                                                                                                L’AUTORE
                                                                                                       android:versionCode=”1”
                                                                        android:versionName=”1.0”>
                                                                  ...                                                              Carlo Pelliccia lavora
                                                                                                                                   presso 4IT (www.4it.it),
                                                                  Siccome le applicazioni Android non possono cam-                 dove si occupa di analisi
                                                                                                                                   e sviluppo software per
                                                                  biare il wallpaper del telefono senza dichiararlo                piattaforme Java. Nella
                                                                  esplicitamente, in accordo con il modello di sicu-               sua carriera di technical
                                                                  rezza del sistema, nel manifest dell’applicazione                writer ha pubblicato cinque
                                                                  è stato necessario dichiarare l’uso del permesso                 manuali ed oltre duecento
                                                                  android.permission.SET_WALLPAPER.                                articoli, molti dei quali
                                                                                                                                   proprio tra le pagine di
                                                                  Ora è tutto pronto, non resta che installare l’ap-               ioProgrammo. Il suo sito,
                                                                  plicazione su un emulatore o su uno smartphone                   che ospita anche diversi
                                                                  ed avviare il servizio di cambio automatico del                  progetti Java Open Source,
                                                                  wallpaper.                                                       è disponibile all’indirizzo
Fig.3: I wallpaper usati a rotazione dell’applicazione vanno                                                                       www.sauronsoftware.it
inseriti al percorso di progetto assets/wallpapers                                                               Carlo Pelliccia



    74
http :/ / www. i o p r o g r a m m o. it                                                                                  Novembre And roi d pr o63 m in g
                                                                                                                                   2010 / g r am
                                                        Applicazioni Android
                                    Applicazioni location-based conlocation-based con Android
                                      MOBILE                                        Android programming




TU SEI QUI!
TE LO DICE ANDROID
I SERVIZI LOCATION-BASED SONO UNA DELLE CARATTERISTICHE PIÙ ATTRAENTI DI
ANDROID. IMPARIAMO A REALIZZARE APPLICAZIONI IN GRADO DI LOCALIZZARE L’UTENTE
VIA GPS E DI DISEGNARE LA SUA POSIZIONE IN UNA MAPPA




                                        U
                                                  n’applicazione o un servizio possono definirsi     è android.location.LocationManager. Riassumendo,
                                                  location-based quando lavorano con il posi-        dall’interno di un’attività, il servizio di localizzazione
                                                  zionamento geografico dell’utente. Google è        si recupera alla seguente maniera:
                                        stato un pioniere dei servizi location-based: Google
                                        Maps e Google Earth hanno spianato la strada ad              LocationManager locationManager = (LocationManager)

                                        una nuova generazione di applicazioni basate sulla                             getSystemService(LOCATION_SERVICE);

                                        geografia e sul posizionamento. Con Android, Google
                                        non smette di innovare. È con l’avvento dei disposi-         I meccanismi di localizzazione disponibili sono classifi-
 ❑ CD ❑ WEB                             tivi mobili, infatti, che le applicazioni location-based     cati come provider. I due provider discussi in precedenza
 Android.rar                            possono finalmente sfruttare a pieno tutte le loro           sono identificati con due costanti:
                                        potenzialità. In questo articolo scopriremo come è
                 cdrom.ioprogrammo.it
                                        facile mostrare mappe, cercare luoghi e interagire con       •	 LocationManager.GPS_PROVIDER, il provider colle-
                                        il ricevitore GPS del telefono.                                gato al ricevitore GPS del telefono.
                                                                                                     •	 LocationManager.NETWORK_PROVIDER, il provider
                                                                                                       che localizza in maniera approssimativa il telefono
                                                                                                       basandosi sulle reti raggiungibili.
                                        LOCATION MANAGER
                                        E PROVIDER                                                   Prima di usare uno di questi due provider, bisogna verifi-
                                        Gli smartphone implementano solitamente uno o                care che sia supportato dal telefono che esegue l’applica-
                                        più meccanismi di localizzazione dell’utente. Il GPS         zione. Per farlo, si può richiamare il metodo getProvider()
                                        è quello più noto ed utilizzato, ma non è l’unico            di LocationManager. Il metodo restituisce null se il pro-
                                        meccanismo disponibile. I dispositivi di ultima gene-        vider non è disponibile, mentre restituisce un risultato
                                        razione, infatti, sono in grado di localizzare la propria    di tipo android.location.LocationProvider nel caso lo sia.
                                        posizione verificando le reti GSM e Wi-Fi disponibili        Ad esempio:
                                        nei paraggi (in questo caso si parla di localizzazione
                                        network-based). Si tratta di un meccanismo di localiz-       LocationProvider gpsProvider = locationManager.

                                        zazione meno accurato rispetto al GPS, ma comunque                       getProvider(LocationManager.GPS_PROVIDER);

                                        affidabile quando è sufficiente conoscere l’area dove        if (gpsProvider == null) {

                                        si trova l’utente, e non si ha bisogno di calcolare la         // GPS non disponibile
               REQUISITI                sua posizione precisa. Android offre un’interfaccia          } else { // GPS disponibile }

                                        di programmazione che si astrae dal meccanismo di
Conoscenze richieste                    localizzazione utilizzato in dal device. Tale interfaccia    Gli oggetti LocationProvider, quando disponibili, forni-
    Basi di Java                        è offerta sotto forma di servizio di sistema. Dall’interno   scono informazioni sul provider richiesto, come la sua
                                        di un’attività, i servizi di sistema possono essere recu-    accuratezza e le caratteristiche supportate. Dopo essersi
Software
                                        perati usando il metodo getSystemService(). Il metodo        accertati che un provider è disponibile, altrettanto impor-
    Java SDK (JDK) 5+,
    Android SDK, Eclipse                richiede in argomento l’identificativo del servizio di       tante è controllare che sia anche attivo. L’utente, infatti,
    3.3+, ADT
                                        sistema desiderato. Gli ID dei servizi di sistema sono       potrebbe averlo disabilitato dalle impostazioni del tele-
Impegno
                                        conservati in alcune costanti. Quello per il servizio di     fono. L’abilitazione di un provider può essere controllata
                                        localizzazione è riportato nella costante LOCATION_          con il metodo isProviderEnabled() di LocationManager.
                                        SERVICE. Il metodo getSystemService(), una volta             Ad esempio:
Tempo di realizzazione                  recuperato il servizio, lo restituisce sotto forma di sem-
                                        plice Object. È dunque necessario eseguire un casting        boolean gpsEnabled = locationManager.isProvider

                                        verso la classe reale del servizio, che in questo caso                      Enabled(LocationManager.GPS_PROVIDER);




        56 / Dicembre 2010
A n d ro id p r o g r a m m ing                                                                                                                               75
                                                                                                                                  h ttp ://www.io p r o g r a m m o .i t
                                    Applicazioni    Applicazioni Android
                         Android programming location-based con location-based con Android
                                                                                 MOBILE


                                                                accadere che un provider sia stato disabilitato in un posto
Prima di usare uno dei due provider, quindi, è meglio           e riabilitato poi a chilometri di distanza, e che quindi la
controllarne lo stato, in modo da suggerire all’utente          sua ultima misurazione sia completamente inservibile.
di abilitarlo prima di procedere. Ancora un’importan-           Per avere “dati freschi” da uno dei provider, gli si deve
te avvertimento: per utilizzare correttamente i servizi         esplicitamente chiedere di inviarli non appena disponi-
di localizzazione, è necessario che l’applicazione, nel         bili. Il metodo utile per farlo è:
proprio manifest, richieda l’uso dei permessi android.
permission.ACCESS_COARSE_LOCATION (per la loca-                 public	 void	 requestLocationUpdates(String	 provider,	
lizzazione basata sui network) e/o android.permission.          long	 minTime,	 float	 minDistance,	 LocationListener	                       NOTA
ACCESS_FINE_LOCATION (per la localizzazione GPS):               listener)
                                                                                                                              GLOBAL
<?xml version=”1.0” encoding=”utf-8”?>                          Gli argomenti hanno il seguente scopo:                        POSITIONING
<manifest ...>                                                                                                                SYSTEM
    <application ...>                                           •	 provider     è l’ID del provider (ad esem-                 GPS è una di quelle sigle che
      ...                                                          pio       LocationManager.GPS_PROVIDER              o      tutti conoscono ma pochi
                                                                   LocationManager.NETWORK_PROVIDER).                         comprendono. GPS sta per
                                                                                                                              Global Positioning System,
                                                                •	 minTime è il numero di secondi minimo che deve             ossia sistema di posizio-
                                                                   intercorrere tra una misurazione e la successiva. Con      namento globale. Si tratta
DOVE MI TROVO?                                                     questo parametro si può evitare che dal provider ven-      di un sistema costituito da
Passiamo a vedere come sia possibile recuperare la posi-           gano troppe informazioni, chiedendo di non mandare         una serie di satelliti artificiali
zione fornita da uno dei provider previsti. Le misurazioni         una nuova lettura se non è passato almeno un certo         in orbita intorno al pianeta.
                                                                                                                              Ciascun satellite trasmette
vengono rappresentate mediante oggetti di tipo android.            numero di secondi.                                         ciclicamente dei messaggi
location.Location. I principali e più importanti metodi         •	 minDistance è la distanza minima, in metri, che deve       verso la superficie. I messaggi
messi a disposizione da questa classe sono:                        esserci tra una misurazione e la successiva. Anche in      contengono il segnale orario
                                                                   questo caso l’argomento serve per filtrare le letture      e delle informazioni sulle
•	 public	long	getTime()	                                          del provider ed evitare che da questo vengano troppe       orbite percorse. Il ricevitore
                                                                                                                              GPS ascolta questi messaggi
   Restituisce la data in cui l’informazione è stata calco-        informazioni, chiedendo di non mandare una nuova           e li elabora. In base al ritardo
   lata, come UNIX timestamp (il numero di millisecondi            lettura se non si è riscontrato uno spostamento di un      dei segnali e ai contenuti dei
   trascorsi dal 1 Gennaio 1970 alle ore 00:00:00 GMT)             certo numero di metri.                                     messaggi, il ricevitore è in
•	 public	double	getLatitude()	                                 •	 listener è l’oggetto, di tipo android.location.            grado di calcolare la propria
   Restituisce la misura di latitudine.                            LocationListener, su cui verranno notificate tutte le      distanza da ciascun satellite.
                                                                                                                              Nel momento in cui il ricevi-
•	 public	double	getLongitude()	                                   misurazioni effettuate e filtrate secondo i parametri      tore riesce ad agganciare il
   Restituisce la misura di longitudine.                           precedenti.                                                segnale di quattro o più satel-
•	 public	boolean	hasAltitude()	                                                                                              liti, diventa possibile applicare
   Restituisce true se la misurazione comprende anche           Ad esempio:                                                   un calcolo matematico simile,
   un dato di altitudine.                                                                                                     nel principio, alla triangola-
                                                                                                                              zione. In questa maniera, il
•	 public	double	getAltitude()	                                 locationManager.requestLocationUpdates(Location
                                                                                                                              ricevitore può determinare la
   Se disponibile, restituisce la misura di altitudine.           Manager.GPS_PROVIDER, 5, 1, myLocationListener);
                                                                                                                              propria posizione sul globo
•	 public	boolean	hasSpeed()	                                                                                                 terracqueo, esprimendola in
   Restituisce true se la misurazione comprende anche           Con questa richiesta si sottoscrive il provider GPS e si      termini di latitudine e longitu-
   un dato di velocità.                                         ricevono le letture e gli eventi provenienti da questo. Le    dine. Più sono i satelliti di cui
                                                                                                                              il dispositivo riceve il segnale,
•	 public	float	getSpeed()	                                     letture, in particolar modo, saranno filtrate: solo se lo     più è accurata la posizione
   Se disponibile, restituisce la misura di velocità. L’unità   spostamento equivale ad almeno un metro, e comunque           calcolata.
   di misura è m/s (metri al secondo).                          non più di una notifica ogni cinque secondi. Letture ed
                                                                eventi saranno segnalati sull’oggetto myLocationListe-
Una maniera semplice e diretta per ottenere una misu-           ner, che naturalmente deve implementare l’interfaccia
razione è domandarla al LocationManager, servendosi             LocationListener. L’implementazione di LocationListener
del metodo getLastKnownLocation(). Il metodo richiede           richiede la definizione dei seguenti metodi:
l’ID del provider da interrogare e restituisce un oggetto
Location. Ad esempio:                                           •	 public	void	onStatusChanged(String	provider,	int	
                                                                  status,	Bundle	extras)
Location location = locationManager.getLastKnown                  Notifica un cambio di stato nel provider in argo-           Fig.1: Dalle impostazioni
        Location(LocationManager.GPS_PROVIDER);                   mento. Il nuovo stato (argomento status) può                di sistema è possibile
                                                                                                                              abilitare o disabilitare i
                                                                  essere: LocationProvider.OUT_OF_SERVICE, se il
                                                                                                                              servizi di localizzazione
Si faccia attenzione al fatto che getLastKnownLocation()          provider è andato fuori servizio; LocationProvider.         integrati. Per questo
non calcola la posizione del telefono nel momento in              TEMPORARILY_UNAVAILABLE, se il provider                     bisogna sempre verificare
cui lo si richiama: il metodo si limita a restituire l’ultima     è diventato temporaneamente non disponibile;                che siano attivi, prima di
                                                                                                                              utilizzarli
misurazione disponibile per il provider richiesto. Può            LocationProvider.AVAILABLE, se il provider è tornato



    76
http :/ / w ww. i o p r o g r a m m o. it                                                                                   2010 / 57
                                                                                                                   Dicembre And roi d pr o g r am m in g
                                                      Applicazioni Android
                                  Applicazioni location-based con location-based con Android
                                    MOBILE                                         Android programming


                                          disponibile.                                                          android:versionName=”1.0” package=

                                     •	 public	void	onProviderEnabled(String	provider)	                                              ”it.ioprogrammo.locationdemo”>

                                        Notifica che il provider indicato in argomento è stato            ...

                                        abilitato.
                                     •	 public	void	onProviderDisabled(String	provider)	
                                        Notifica che il provider indicato in argomento è stato
                                        disabilitato.                                                     EMULARE IL GPS
                                     •	 public	void	onLocationChanged(Location	location)                  Quando si sviluppa un’applicazione location-based,
                                        Notifica la lettura di una nuova posizione.                       come l’esempio appena illustrato, ci si scontra con il pro-
                                                                                                          blema di come eseguirne il test ed il debug. Naturalmente
               NOTA                  Una volta che non occorre più conoscere le misurazioni               è possibile installare l’applicazione su uno smartphone
                                     provenienti dal location provider selezionato, è meglio              ed andare a farsi un giro a piedi o in automobile, tuttavia
           COORDINATE                annullare la sottoscrizione svolta in precedenza, agendo             questa non è la maniera migliore per test frequenti e
           GPS DA RIGA               sul LocationManager con il metodo removeUpdates():                   debug efficaci. Per nostra fortuna è possibile impostare
           DI COMANDO                                                                                     delle false coordinate geografiche sull’emulatore fornito
   Se non utilizzate Eclipse,         locationManager.removeUpdates(myLocationListener);                  con l’SDK. Con Eclipse lo si fa dalla scheda “Emulator
   potete fornire false coor-                                                                             Control” della prospettiva “DDMS”. È possibile fornire
   dinate GPS all’emulatore                                                                               coordinate semplici, oppure caricarne una lista comples-
   usando la riga di coman-
     do. Aprite il prompt dei                                                                             sa da file di tipo GPX e KML. Attenzione: se le coordinate
    comandi e connettetevi           LOCATIONDEMO                                                         inviate tramite l’Emulator Control di Eclipse DDMS non
    all’emulatore via telnet:        Forti delle nozioni appena acquisite, andiamo a realizza-            funzionano correttamente, provate a chiudere l’ambien-
                                     re un’applicazione che le metta in pratica. Chiameremo               te e a riavviarlo dopo aver aggiunto le seguenti righe al
    telnet localhost <porta>         l’applicazione LocationDemo. Definiamone il layout nel               file eclipse.ini presente nella cartelle di installazione del
   La porta usata dall’emu-          file res/layout/main.xml:                                            vostro Eclipse:
 latore è riportata nel titolo
della finestra che lo contie-         <?xml version=”1.0” encoding=”utf-8”?>                              -Duser.country=US
ne. In genere è 5554 o una            <LinearLayout xmlns:android=”http://schemas.android.                -Duser.language=en
cifra molto simile. Lanciate                                                  com/apk/res/android”
             ora il comando:            android:orientation=”vertical” android:layout_
                                                                                 width=”fill_parent”
 geo fix <longitude> <lati-
                    tude>               android:layout_height=”fill_parent”>                              GOOGLE APIS
                                      …                                                                   PER ANDROID
                   Ad esempio:                                                                            Finora abbiamo appreso come accedere al servizio di
           geo fix 12.484564         Si tratta di un layout molto semplice, che realizza una              localizzazione di Android per conoscere la posizione
                    41.91247         tabella all’interno della quale andremo ad annotare i dati           dell’utente, ma questo è soltanto l’inizio. Una vera e pro-
                                     provenienti dal provider GPS.                                        pria applicazione location-based, infatti, fa anche uso di
                                     Andiamo all’attività LocationDemoActivity, che realizza              mappe e di altri servizi analoghi. Poiché questo è un ter-
                                     la logica del progetto appena descritta:                             reno in cui Google gioca in casa, abbiamo a nostra dispo-
                                                                                                          sizione un’ottima libreria di classi per l’accesso facilitato
                                      package it.ioprogrammo.locationdemo;                                ai servizi location-based di Mountain View. Purtroppo
                                      import java.util.Date;                                              tale libreria, per motivi di licensing, viene fornita sepa-
                                      ...                                                                 ratamente dal sistema, e per questo richiede del lavoro
                                      public class LocationDemoActivity extends Activity {                preparatorio aggiuntivo. Per prima cosa è necessario
                                            …                                                             aver scaricato e integrato la libreria nel proprio Android
                                                                                                          SDK. Potete verificarlo avviando il manager dei disposi-
                                     Notate come l’utilizzo del servizio di localizzazione è              tivi virtuali e controllando che nell’elenco dei pacchetti
                                     stato collegato al ciclo di vita dell’attività: si sono utilizzati   installati (“Installed Packages”) sia presente un pacchetto
                                     i metodi onResume() e onPause(), rispettivamente, per                del tipo “Google APIs by Google Inc.”, associato alla ver-
Fig.2: LocationDemo è                avviare ed interrompere l’utilizzo del servizio. In que-             sione di Android per la quale state sviluppando. Se non
un’app che si collega al ri-         sta maniera il localizzatore viene invocato solo quando              lo trovate, muovetevi nella scheda “Available Packages” e
cevitore GPS e ne mostra
                                     l’attività sta occupando il display, e non quando gira               scaricatelo. Ad operazione completata create un disposi-
le letture sul display
                                     in background.Non resta che mettere tutto insieme in                 tivo virtuale che supporti le Google API appena installate
                                     AndroidManifest.xml:                                                 (lo potete fare dalla scheda “Virtual Devices”). In Eclipse,
                                                                                                          quando creerete una nuova applicazione che usa le
                                      <?xml version=”1.0” encoding=”utf-8”?>                              mappe di Google, ricordatevi di indicare esplicitamente
                                      <manifest xmlns:android=”http://schemas.android.com/                l’utilizzo della libreria nel target del progetto. L’ambiente,
                                                                                   apk/res/android”       creando il nuovo progetto, aggiungerà la libreria al build
                                            android:versionCode=”1”                                       path dell’applicazione. Se non utilizzate Eclipse dovrete


        58 / Dicembre 2010
A n d ro id p r o g r a m m ing                                                                                                                                     77
                                                                                                                                        h ttp ://www.io p r o g r a m m o .i t
                                    Applicazioni    Applicazioni Android
                         Android programming location-based conlocation-based con Android
                                                                                MOBILE


svolgere questo compito a mano. I JAR delle Google API            e per ognuno di essi vi fornirà l’impronta MD5. Con il
li trovate a partire dal percorso <android-sdk-directory>/        browser, recatevi ora all’indirizzo: http://code.google.
add-ons. Accertatevi, infine, che nel manifest della vostre       com/android/add-ons/google-apis/maps-api-signup.
applicazioni location-based siano comprese la dichiara-           html
zione di utilizzo della libreria Google Maps e le clausole
di utilizzo dei permessi per l’accesso al location manager        Accettate le condizioni proposte e inserite l’MD5 del cer-
e ad Internet. Solitamente lo scheletro del manifest di           tificato per il quale volete ottenere una chiave di utilizzo
un’app location-based assomiglia al seguente:                     di Google Maps. È fatta! Salvate la pagina Web con la
                                                                  chiave generata per il vostro certificato.
<?xml version=”1.0” encoding=”utf-8”?>                                                                                                      SUL WEB
<manifest ...>
    <application ...>                                                                                                            GOOGLE MAPS API
      <uses-library android:name=”com.google.android.             MAPACTIVITY                                                    REFERENCE
                                                       maps” />   E MAPVIEW                                                      La reference guide per
      ...                                                         Il pacchetto di riferimento per le API Android di Google       le Google Maps API di
    </application>                                                Maps è com.google.android.maps. All’interno vi trovate         Android è all’indirizzo:
    <uses-permission android:name=”android.permission.            MapActivity, che è la classe da estendere nel caso in cui si   http://code.google.com/
                                       ACCESS_FINE_LOCATION” />   voglia realizzare un’attività che mostri delle mappe sullo     android/add-ons/google-
    <uses-permission android:name=”android.permission.            schermo. Estendere MapActivity è esattamente come              apis/reference/index.html
                                  ACCESS_COARSE_LOCATION” />      estendere Activity, con l’unica differenza che si deve
    <uses-permission android:name=”android.permission.            implementare il metodo:
                                                    INTERNET”/>
</manifest>                                                       protected boolean isRouteDisplayed()


                                                                  A questo metodo dobbiamo far restituire true quando si
                                                                  sta visualizzando una mappa con delle indicazioni stra-
GOOGLE MAPS KEY                                                   dali (ad esempio un percorso da un punto A ad un punto
Ancora un passo ci separa dal poter mostrare mappe sul            B). In tutti gli altri casi si deve restituire false.
display del nostro dispositivo: dobbiamo ottenere una             L’altra differenza tra Activity e MapActivity è che, all’in-
chiave (key) per l’accesso al servizio Google Maps. Per           terno di quest’ultima, è possibile introdurre un widget
farlo dobbiamo fornire a Google l’impronta MD5 del                di tipo MapView. Si tratta del componente in grado di
certificato che utilizziamo per firmare le nostre applica-        mostrare le mappe provenienti dai server di Google.            Fig.4: Con l’Emulator Con-
zioni. Siccome solitamente si utilizza un certificato per         Potete dichiarare il componente di tipo MapView in un          trol di Eclipse DDMS è
                                                                                                                                 possibile inviare all’emu-
lo sviluppo ed uno per il rilascio, sarà probabilmente            layout XML, da caricare poi all’interno della MapActivity:
                                                                                                                                 latore false coordinate
necessario ottenere ed utilizzare due chiavi differenti.                                                                         di localizzazione
Il certificato per lo sviluppo ed il debug è compreso nel         <com.google.android.maps.MapView

keystore che trovate ad uno dei seguenti percorsi:                   android:apiKey=”CHIAVE GOOGLE MAPS QUI”
                                                                     android:id=”@+id/mapView”

•	 Windows     Vista: C:\Users\<username>\.android\                  android:layout_width=”fill_parent”

   debug.keystore                                                    android:layout_height=”fill_parent” />

•	 Windows XP: C:\Documents and Settings\<username>\.
   android\debug.keystore                                         Il widget potrà poi essere recuperato dall’interno della
•	 MacOS X e Linux: ~/.android/debug.keystore                     MapActivity, facendo:

In Eclipse potete verificare il percorso del keystore di          MapView mapView = (MapView) findViewById(R.
debug aprendo le preferenze dell’ambiente ed entrando
nella voce “Android » Build”.
L’impronta MD5 di un certificato può essere calcolata
usando l’utility keytool, compresa in ogni Java SDK. Con il
prompt dei comandi posizionatevi all’interno della direc-                                                                        Fig.5: L’utilizzo delle
tory bin del vostro JDK, in modo che il comando keytool                                                                          Google API va indicato
                                                                                                                                 come target del nuovo
sia a portata di lancio. Quindi eseguite il comando:
                                                                                                                                 progetto Android che si
                                                                                                                                 sta creando in Eclipse
keytool -keystore <percorso-keystore> -list


Vi sarà richiesta la password del keystore. La password di
default del keystore di debug è android. Adesso keytool           Fig.3: Le API di Google per la gestione delle mappe van-
vi mostrerà l’elenco dei certificati compresi nel keystore,       no scaricate ed installate separatamente dal sistema



   78
http :/ / w ww. i o p r o g r a m m o. it                                                                                      2010 / 59
                                                                                                                      Dicembre And roi d pr o g r am m in g
                                                      Applicazioni Android
                                  Applicazioni location-based conlocation-based con Android
                                    MOBILE                                        Android programming


                                     id.mapView);                                                        Questo file realizza un layout dove la mappa di Google
                                     A questo punto i metodi di MapView possono essere                   è il componente principale, ed in alto sono posti tre
                                     invocati per controllare la mappa mostrata. Diamo uno               checkbox: “Satellite”, “Traffic” e “Street View”. Li utilizze-
                                     sguardo ai metodi di più comune utilizzo:                           remo per consentire all’utente di abilitare o disabilitare
                                                                                                         le corrispondenti caratteristiche. Passiamo ora all’attività
                                     •	 public	void	setSatellite(boolean	on)	                            MapDemoActivity:
                                       Attiva o disattiva la vista da satellite.
                                     •	 public	boolean	isSatellite()	                                    package it.ioprogrammo.mapdemo;

                                        Controlla se la vista da satellite è attiva oppure no.           ...

                                     •	 public	void	setStreetView(boolean	on)	                           import com.google.android.maps.MapActivity;

                                        Attiva o disattiva i tracciati che mostrano dove street          import com.google.android.maps.MapView;

                                        view è disponibile.                                              ...

                                     •	 public	void	setClickable(boolean	on)	                            public class MapDemoActivity extends MapActivity {

                                        Rende la mappa cliccabile oppure no. Se la mappa è               ...

                                        cliccabile (e per default non lo è), l’utente può control-
                                        larla con il tocco del dito.                                     Qui, con veramente poche righe di codice, si riesce a
                                     •	 public	 void	 setBuiltInZoomControls(boolean	 on)	               collegare i tre checkbox di cui sopra al widget MapView.
                                        Attiva o disattiva i controlli incorporati per lo zoom           Manca solo l’AndroidManifest.xml:
                                        della mappa.
                                     •	 public	int	getZoomLevel()	                                       <?xml version=”1.0” encoding=”utf-8”?>

                                        Restituisce il livello di zoom corrente, che sarà sempre         <manifest xmlns:android=”http://schemas.android.com/

                                        compreso tra 1 e 21.                                                                                           apk/res/android”

                                     •	 public	GeoPoint	getMapCenter()	
                                        Restituisce le coordinate geografiche del punto centra-                package=”it.ioprogrammo.mapdemo”

                                        le della mappa.                                                                                     android:versionCode=”1”
                                                                                                         ...

                                     Gli oggetti GeoPoint, come è facile intuire, sono uti-
                                     lizzati per esprimere una posizione terrestre. Il solo
                                     costruttore disponibile è: public GeoPoint(int latitudeE6,
                                     int longitudeE6)	 	 Latitudine e longitudine, in questo             CONTROLLARE
               NOTA                  caso, sono espressi mediante degli interi. Nel caso del             LA MAPPA
                                     LocationManager, come abbiamo visto in precedenza,                  Rendendo un widget MapView cliccabile e abilitando i
   EVENTI DI TOUCH                   sono invece espressi con valori double. Passare da una              controlli per lo zoom compresi nel widget, l’utente può
    SUGLI OVERLAY                    notazione all’altra è molto semplice:                               scorrere la mappa e controllare ciò che più lo aggrada.
Gli overlay possono essere                                                                               Per controllare la mappa in maniera automatica, inve-
 interattivi. Per riscontrare         int asInt = (int) Math.floor(asDouble * 1.0E6);                    ce, è possibile farsi restituire da MapView un oggetto
   eventuali eventi di tocco                                                                             di tipo MapController, grazie al metodo getController():
 o di tastiera riscontrati su
   di essi, si possono ride-         Le coordinate contenute in un oggetto GeoPoint possono              MapController mapController = mapView.getController();
  finire i metodi di Overlay         essere recuperate con i metodi getLatitudeE6() e getLon-            Con il MapController si possono fare diverse cose, tra cui:
  onTap(), onTouchEvent(),           gitudeE6(). Per passare dalla notazione intera a quella
onKeyDown() e onKeyUp().             decimale si può fare:                                               •	 public	boolean	zoomIn()
                                                                                                            Aumenta lo zoom di un livello. Restituisce true se
                                      double asDouble = asInt / 1.0E6;                                      l’operazione riesce, false se il livello di zoom è già al
                                                                                                            massimo.
                                                                                                         •	 public	boolean	zoomOut()	
                                                                                                            Diminuisce lo zoom di un livello. Restituisce true se
                                     MAPDEMO                                                                l’operazione riesce, false se il livello di zoom è già al
                                     Realizziamo insieme un primo esperimento con le                        massimo.
                                     mappe. Chiameremo l’applicazione MapDemo. Ecco il                   •	 public	int	setZoom(int	zoomLevel)	
                                     suo layout da conservare sul file res/layout/main.xml:                 Imposta il livello di zoom della mappa, che va espres-
                                                                                                            so come valore compreso tra 1 e 21. Restituisce il livel-
                                      <?xml version=”1.0” encoding=”utf-8”?>                                lo di zoom effettivamente impostato.
                                      <LinearLayout xmlns:android=”http://schemas.android.               •	 public	void	setCenter(GeoPoint	point)	
                                                                             com/apk/res/android”           Sposta la mappa in modo che il punto indicato sia al
                                       android:orientation=”vertical” android:layout_                       centro.
                                                                                   width=”fill_parent”   •	 public	void	animateTo(GeoPoint	point)	
                                       android:layout_height=”fill_parent”>                                 Fa muovere la mappa, mediante un’animazione, fino
                                       ...                                                                  al punto indicato.


        60 / Dicembre 2010
A n d ro id p r o g r a m m ing                                                                                                                                    79
                                                                                                                                       h ttp ://www.io p r o g r a m m o .i t
                                    Applicazioni    Applicazioni Android
                         Android programming location-based conlocation-based con Android
                                                                                MOBILE


                                                               public	 void	 draw(android.graphics.Canvas	 canvas,	
                                                               MapView	mapView,	boolean	shadow)

                                                               Questo metodo viene invocato automaticamente per
                                                               richiedere il disegno dell’overlay. L’argomento canvas è
                                                               un pannello sul quale è possibile fare disegno libero (ce
                                                               ne occuperemo più nel dettaglio in un episodio futuro),
                                                               mapView è la mappa di riferimento e shadow, infine,
Fig.6: La chiave per l’utilizzo delle Google Maps API va       indica se si deve disegnare o meno l’ombra dell’overlay
richiesta online fornendo l’impronta MD5 del certificato       che si sta realizzando. Il metodo viene sempre chiamato
che sarà usato per firmare l’applicazione Android
                                                               due volte: la prima volta con shadow pari a true, per dise-
                                                               gnare l’ombra, la seconda con shadow pari a false, per
                                                               disegnare il contenuto di primo piano dell’overlay. Se non
Ora che siamo in grado di manipolare la mappa                  si è interessati all’ombra, è sufficiente non far nulla quan-
mostrata, proviamo a collegare l’esempio del paragrafo         do shadow è uguale a true. Il problema che sorge, a questo
precedente con il servizio di localizzazione studiato          punto, è che sugli oggetti Canvas si disegna ragionando in
nella prima parte dell’articolo. Facciamo in modo che          termini di coordinate x ed y, mentre le mappe ed i servizi
l’attività, una volta avviata, inizi ad ascoltare le coordi-   di localizzazione lavorano con le coordinate geografiche
nate provenienti dal ricevitore GPS, centrando di volta        latitudine e longitudine. Come fare, quindi, per disegnare
in volta la mappa sulla posizione letta. Incrementiamo         qualcosa alla coordinata (x, y) che corrisponde esatta-
anche il valore di zoom di partenza, in modo da evi-           mente ad una posizione (lat, lon) della mappa? Si può
denziare meglio la posizione dell’utente. Modifichiamo         passare da una notazione all’altra estraendo un oggetto
l’attività MapDemoActivity, aggiungendole quanto               Projection dal MapView in uso:
indicato nel seguente stralcio:
                                                               Projection projection = mapView.getProjection();                Fig.7: La posizione indi-
...                                                                                                                            cata dal ricevitore GPS
import com.google.android.maps.GeoPoint;                                                                                       viene evidenziata sulla
                                                               Con un oggetto Projection si può passare da coordinate
                                                                                                                               mappa grazie ad una
import com.google.android.maps.MapController;                  geografiche a coordinate di disegno, grazie al metodo:          freccia disegnata in un
public class MapDemoActivity extends MapActivity {                                                                             overlay della mappa
...                                                            public	 android.graphics.Point	 toPixels(GeoPoint	 in,	
                                                               android.graphics.Point	out)
Completiamo l’opera aggiungendo l’uso del permes-
so android.permission.ACCESS_FINE_LOCATION nel                 Le coordinate del GeoPoint vengono convertite e salvate
manifest dell’applicazione.                                    in un oggetto Point, che contiene delle semplici coordi-
                                                               nate x ed y. Si può eseguire anche la conversione inversa,
                                                               grazie al metodo:

OVERLAY                                                        public	GeoPoint	fromPixels(int	x,	int	y)
Quando un’applicazione mostra una mappa, il più delle
volte è perché vuole indicare qualcosa, magari attraverso      Andiamo ad apportare l’ultima miglioria alla nostra appli-
un disegno sovrapposto alla mappa stessa. Ad esempio,          cazione MapDemo. Aggiungiamo fra le sue risorse un’im-
si è soliti inserire una freccia che indica la posizione       magine youarehere.png (la trovate nel codice allegato),                     L’AUTORE
dell’utente e dei baloon per evidenziare i luoghi di suo       che rappresenta una freccia puntata verso il basso. Va
interesse che sono nei paraggi. In gergo si dice che alla      disposta al percorso di progetto res/drawable/youarehere.       Carlo Pelliccia lavora
mappa vengono sovrapposti degli overlay, ognuno dei            png. La useremo in un overlay che indicherà all’utente          presso 4IT (www.4it.it),
quali mostra qualcosa in particolare. Gli overlay sovrap-      dove si trova. Modifichiamo ancora una volta l’attività         dove si occupa di analisi
                                                                                                                               e sviluppo software per
posti ad un widget MapView possono essere recuperati e         MapDemoActivity, con le aggiunge mostrate di seguito:           piattaforme Java. Nella
controllati grazie al metodo:                                                                                                  sua carriera di technical
                                                               package it.ioprogrammo.mapdemo;                                 writer ha pubblicato cinque
public java.util.List<Overlay> getOverlays()                   ...                                                             manuali ed oltre duecento
                                                                     private class CurrentPositionOverlay extends Overlay {    articoli, molti dei quali
                                                               …                                                               proprio tra le pagine di
Un nuovo overlay può essere aggiunto alla lista facendo:                                                                       ioProgrammo. Il suo sito,
                                                                                                                               che ospita anche diversi
mapView.getOverlays().add(new MyOverlay());                    Non resta che caricare l’applicazione su un dispositivo         progetti Java Open Source,
                                                               Android ed andarsi a fare un giro per la propria città.         è disponibile all’indirizzo
Per realizzare un overlay personalizzato si deve estendere     Buona passeggiata!                                              www.sauronsoftware.it
la classe Overlay. Il metodo che più comunemente viene
ridefinito è:                                                                                                Carlo Pelliccia



      80
http :/ / w ww. i o p r o g r a m m o. it                                                                                     2010 / 61
                                                                                                                     Dicembre And roi d pr o g r am m in g
                                         Applicazioni Inventor
    Applicazioni Android senza scrivere codice con AppAndroid senza scrivere codice con App Inventor
              COVER STORY                                              Android programming




APP ANDROID FACILI
CON APP INVENTOR
APP INVENTOR È IL NUOVO SISTEMA DI GOOGLE PER CREARE APPLICAZIONI ANDROID SENZA
SCRIVERE UNA SOLA RIGA DI CODICE. SCOPRIAMO IN COSA CONSISTE E UTILIZZIAMOLO
PER REALIZZARE FACILMENTE LE NOSTRE IDEE




                                        L
                                                e applicazioni contano. Questa è la conclu-      e vendere (o regalare) delle applicazioni Android
                                                sione alla quale sono finalmente giunti tutti    competitive. Insomma, basta l’idea.
                                                i produttori di smartphone di ultima genera-
                                        zione. Non basta più proporre un hardware poten-
                                        te, un design accattivante e un sistema facile da
                                        utilizzare: ci vuole anche un ampio parco di appli-      PREREQUISITI
                                        cazioni, possibilmente di alta qualità. Non si fanno     App Inventor è un’applicazione web online, come
                                        discriminazioni per genere, utilità o complessità:       GMail o Facebook per intenderci, e perciò per
                                        l’utente moderno, sul market del suo smartphone,         accedere all’applicazione bastano un computer ed
 ❑ CD ❑ WEB
 appinv.zip                             vuole trovare di tutto: dallo strumento di lavoro al     un browser di comune fattura. Più nello specifico, i
                                        passatempo, dall’applicazione per interagire con il      sistemi attualmente supportati sono:
                 cdrom.ioprogrammo.it
                                        suo social network preferito a quella utile per risol-
                                        vere una piccola faccenda di tutti i giorni.             •	 Windows: XP, Vista, 7
                                        Google tutto ciò l’ha capito benissimo e per questo      •	 Mac OS X: 10.5, 10.6
                                        la mamma di Android coccola ed incentiva chiun-          •	 GNU/Linux: Ubuntu 8+, Debian 5+
                                        que abbia nuove idee per applicazioni di successo.
                                        Gli sviluppatori che hanno scelto Android, infatti,      I browser compatibili, invece, sono:
                                        hanno vita facile: hanno a disposizione un lin-
                                        guaggio di programmazione facile ed espressivo,          •	 Mozilla Firefox 3.6 o successivo
                                        una libreria di funzionalità potenti e complete, un      •	 Apple Safari 5.0 o successivo
                                        ambiente di sviluppo aperto e flessibile. La docu-       •	 Google Chrome 4.0 o successivo
                                        mentazione e gli articoli tecnici non mancano, così      •	 Microsoft Internet Explorer 7 o successivo
                                        come abbondanti sono le comunità online dove gli
                                        sviluppatori Android si radunano e si danno aiuto        È poi importante che il sistema ed il browser instal-
                                        a vicenda. Programmare applicazioni per Android,         lino Java 6. Per verificare ed eventualmente soddi-
                                        insomma, è facile e divertente. A Google, però,          sfare questo ulteriore requisito, è sufficiente colle-
                                        questo non basta. La programmazione, infatti, è          garsi a questa pagina www.java.com. Per verificare
                                        molto importante per avere buone applicazioni, e         il vostro sistema seguite il link “Io ho Java?”. In caso
                                        per questo va incentivata, ma allo stesso tempo la       di esito negativo, procedete al download e all’instal-
                                        necessità di scrivere del codice è un limite per chi     lazione dal sito stesso.
                                        non ha studiato informatica. Insomma, per quanto
               REQUISITI
                                        facile e divertente possa essere lo sviluppo delle
                                        applicazioni Android, la capacità di scrivere del
Conoscenze richieste
    -
                                        buon codice resta sempre appannaggio degli addet-        SETUP DEL SOFTWARE
                                        ti ai lavori o di chi studia per diventarlo.             Benché l’App Inventor in sé, essendo un’applica-
Software                                Per questo motivo Google sta gradualmente intro-         zione online, non necessiti dell’installazione di
    Java 6                              ducendo App Inventor, un sistema alternativo per         ulteriore software per lo sviluppo delle applica-
                                        creare applicazioni Android senza scrivere una sola      zioni Android, conviene comunque scaricare ed
Impegno                                 riga di codice. Grazie ad App Inventor le applica-       installare un package aggiuntivo, chiamato App
                                        zioni possono essere letteralmente disegnate sullo       Inventor Setup Software. Il pacchetto contiene degli
Tempo di realizzazione                  schermo del proprio computer. Apprendendo alcu-          strumenti aggiuntivi per la verifica ed il confezio-
                                        ni principi di base, tra l’altro molto semplici, si      namento delle applicazioni e serve soprattutto per
                                        diventa velocemente in grado di creare, verificare       verificare le applicazioni realizzate su un dispositi-


        12 / Gennaio 2011
A n d ro id p r o g r a m m ing                                                                                                                         81
                                                                                                                            h ttp ://www.io pr o g r a m m o .i t
     Applicazioni Android senza scrivere codice con App Inventor scrivere codice STORY Inventor
              Android programming           Applicazioni Android senza  COVER con App


vo reale connesso via USB al computer, oppure in          CREARE UN ACCOUNT
alternativa su un emulatore.                              Soddisfatti i requisiti hardware e software, biso-
A seconda del vostro sistema operativo, collegatevi       gna ottenere l’accesso all’applicazione online.
ad uno fra i seguenti indirizzi:                          Come si diceva sopra, infatti, App Inventor è come
                                                          Facebook o GMail. Per accedervi bisogna avere un
Windows:                                                  account e chiedere l’abilitazione all’uso del servi-
http://appinventor.googlelabs.com/learn/                  zio. Collegatevi quindi all’indirizzo: appinventor.
setup/setupwindows.html                                   googlelabs.com
                                                          Se avete già un account Google potete accedere
GNU/Linux:                                                direttamente (box evidenziato in blu in Fig.2), altri-
http://appinventor.googlelabs.com/learn/                  menti seguite il link per iscrivervi (box evidenziato
setup/setuplinux.html                                     in rosso). Dopo aver soddisfatto il requisito dell’ac-
                                                          count e dell’accesso ai servizi Google, bisogna com-
Mac OS X:                                                 pilare un ulteriore modulo per richiedere l’accesso
http://appinventor.googlelabs.com/learn/                  alla piattaforma (link evidenziato in verde).
setup/setupmac.html                                                                                                             NOTA


Scaricate ed installate il pacchetto, secondo le istru-                                                             SAVE E SAVE AS
zioni riportate nella pagina. Per verificare che l’in-                                                              Il bottone “Save” pre-
stallazione sia andata a buon fine, recatevi nella                                                                  sente nell’interfaccia di
directory in cui è stato installato il software ed                                                                  App Inventor permette di
                                                                                                                    salvare, di tanto in tanto,
avviate il comando run-emulator. Come il nome                                                                       il lavoro svolto. Benché
lascia intuire, questo comando avvia l’emulatore                                                                    la piattaforma svolga
del sistema Android compreso nel pacchetto. Se                                                                      comunque dei salvataggi
tutto è andato a buon fine, dopo qualche minuto di                                                                  automatici, vi consigliamo
attesa, dovreste ottenere sul vostro desktop l’emu-       Fig. 2: La pagina di accesso ad App Inventor
                                                                                                                    di utilizzarlo ogni volta che
                                                                                                                    avete concluso un lotto di
lazione della più recente piattaforma Android,                                                                      modifiche. Il tasto “Save
come mostrato in Fig.1 Prendete inoltre nota del                                                                    As”, invece, permette di
percorso di installazione del software appena con-        App Inventor, infatti, è una tecnologia ancora in         salvare il lavoro attuale in
figurato: più tardi questa informazione potrebbe          beta, e perciò non è ancora aperta all’utilizzo da        un altro progetto, diverso
tornare utile.                                            parte del grande pubblico. È tradizione di Google,        da quello di partenza.
                                                          infatti, sperimentare le nuove soluzioni con una
                                                          cerchia ristretta di utenti, per renderle poi pubbli-
                                                          che successivamente. Anche con GMail ed altre
                                                          celebri applicazioni online si fece in questa manie-
                                                          ra. Compilate dunque il modulo di richiesta (l’unico
                                                          dato effettivamente indispensabile che dovete for-
                                                          nire è il vostro indirizzo @gmail.com), inviatelo con
                                                          il tasto “Submit” ed attendete fiduciosi. Solitamente
                                                          non bisogna attendere a lungo: in alcuni casi fortu-
                                                          nati poche ore, in altri qualche giorno. Controllate
                                                          comunque regolarmente la casella di posta che
                                                          avete segnalato, visto che è lì che riceverete la
                                                          notifica di avvenuta attivazione del servizio per il
                                                          vostro account. Non appena sarete abilitati, tornate
                                                          all’indirizzo dell’App Inventor riportato sopra ed
                                                          accedete finalmente alla piattaforma.




                                                          CREARE UN NUOVO
                                                          PROGETTO
                                                          Iniziamo ad imparare come funziona App Inventor.
                                                          La piattaforma è organizzata per progetti. Ogni
                                                          applicazione Android che vogliamo realizzare fa
                                                          parte di un progetto differente. Per questo, non
Fig. 1: L’emulatore Android compreso nell’App Inventor    appena si accede ad App Inventor, la prima cosa
Setup Software                                            che viene visualizzata è l’elenco dei progetti sui



   82
h ttp :/ / www. i o p r o g r a m m o. it                                                                          2011 / 13
                                                                                                           Gennaio And roi d pr o g r am m in g
                                         Applicazioni Inventor
    Applicazioni Android senza scrivere codice con AppAndroid senza scrivere codice con App Inventor
              COVER STORY                                              Android programming


                                                                                               troverete i bottoni, le etichette e le immagini citati
                                                                                               prima, mentre tra quelli più avanzati troverete cose
                                                                                               come i riproduttori di suoni e di video, o i compo-
                                                                                               nenti per interagire con l’accelerometro ed il ricevi-
                                  Fig. 3: La pagina principale di App Inventor, con l’elenco   tore GPS del telefono.
                                  dei progetti inizialmente vuoto



                                  quali si sta lavorando. Appena ci si è iscritti, natural-    DESIGN
                                  mente, non si sta lavorando ancora su alcun proget-          DI UN’APPLICAZIONE
                                  to, e quindi sarà anzitutto necessario crearne uno.          Per prendere confidenza con App Inventor andia-
                                  Azionate il bottone “New”. Vi sarà chiesto di asse-          mo a realizzare insieme un primo semplice ma
                                  gnare un nome al nuovo progetto. I nomi dei pro-             valido esempio. Realizzeremo un’applicazione che,
                                  getti devono essere semplici: possono contenere              una volta lanciata, mostri l’immagine di un’auto-
                                  solo lettere, numeri e caratteri underscore, e non           mobile. Sotto questa immagine ci sarà un pulsante,
                                  possono inglobare spazi o altri caratteri specia-            con il messaggio “Metti in moto”. Quando l’utente
                                  li. Digitiamo il nome di progetto “prima_appli-              premerà il bottone, il telefono dovrà riprodurre
                                  cazione” e confermiamo. Il nuovo progetto sarà               il suono del rombo di un motore. Grazie ad App
                                  creato ed aperto automaticamente. La schermata               Inventor siamo in grado di farlo in pochissimi
                                  presentata a questo punto da App Inventor è il               minuti.
                                  principale banco di lavoro della piattaforma, nel            Per prima cosa ci serve il materiale di base, cioè
                                  quale è possibile costruire l’applicazione. Al centro        un’immagine formato JPG di un’automobile ed un
               NOTA               dello schermo c’è l’anteprima di come si presenta il         file MP3 con il rombo del motore. Potete cercarli
                                  software in lavorazione. Sulla sinistra c’è invece la        su Internet, oppure utilizzare quelli compresi nel
            CHECKPOINT            palette dei componenti. Un componente, nel gergo             CD-Rom allegato alla rivista.
      Il bottone “checkpoint”     di App Inventor, è un elemento di base che è possi-          Costruiamo l’interfaccia grafica di cui abbiamo
    salva un’istantanea dello                                                                  bisogno. Dalla palette, nel gruppo “Basic”, selezio-
    stato attuale del progetto                                                                 niamo il componente “Image” (immagine) e trasci-
  in modo tale che, succes-
     sivamente, sia possibile                                                                  niamolo con il mouse all’interno dell’applicazione.
    recuperarla e ripristinare
così una situazione antece-
 dente. Immaginate di voler
      provare ad applicare al
  vostro progetto una modi-
 fica di cui non siete sicuri.
    Create un checkpoint del      Fig. 4: La maschera per la creazione di un nuovo
    progetto ed applicate poi     progetto
    la modifica: se decidere-
      te di annullarla, potrete
      tornare a lavorare sulla
  versione antecedente così       bile impiegare nella costruzione dell’applicazione,
   come era al momento del        come fosse un mattone. Esempi di componenti                  Fig. 6: Per aggiungere un componente all’applicazione
                   checkpoint.    sono i bottoni, le immagini, le etichette con dei            è sufficiente trascinarlo dalla palette all’anteprima
                                  messaggi di testo e così via. Le applicazioni ven-
                                  gono costruite combinando insieme una serie di
                                  componenti. La palette dei componenti è suddivisa            Trasciniamo anche il componente “Button” (botto-
                                  in differenti categorie, che comprendono un po’ di           ne), posizionandolo subito sotto l’immagine.
                                  tutto. Per capirci meglio: tra i componenti di base          Nella palette dei componenti localizziamo ora
                                                                                               il componente “Sound”, compreso nel gruppo
                                                                                               “Media”. Trasciniamo anche questo all’interno
                                                                                               della applicazione. A differenza degli altri due com-
                                                                                               ponenti, “Sound” è invisibile, non ha cioè elementi
                                                                                               di interfaccia. Non stupitevi, pertanto, se dopo
                                                                                               averlo trascinato non noterete alcuna differenza
                                                                                               nell’anteprima dell’applicazione.
                                                                                               Dopo aver popolato l’applicazione con tutti i com-
                                                                                               ponenti necessari, diamo un’occhiata sulla destra.
                                                                                               Ci sono tre aree molto importanti:

                                  Fig. 5: Il nuovo progetto creato                             •	 Components.     In quest’area vengono ripor-


        14 / Gennaio 2011
A n d ro id p r o g r a m m ing                                                                                                                       83
                                                                                                                          h ttp ://www.io p r o g r a m m o .i t
     Applicazioni Android senza scrivere codice con App Inventor scrivere codice STORY Inventor
              Android programming           Applicazioni Android senza  COVER con App


                                                         “Sound1”. Non dobbiamo far altro che associargli
                                                         l’MP3 caricato in precedenza.




                                                         BLOCKS EDITOR
                                                         L’interfaccia dell’applicazione, a questo punto, è
                                                         pronta: non ci sono né altri componenti da aggiun-
Fig. 7: Le aree “Components”, “Media” e “Properties”     gere né altri file multimediali da caricare. Manca
permettono di gestire ciascun componente presente        però qualcosa. Dobbiamo ancora fare in modo                             NOTA
nell’applicazione
                                                         che quando l’utente aziona il bottone, il rombo del
                                                                                                                     SCARICARE
                                                                                                                     I SORGENTI
   tati tutti i componenti usati nell’applicazione.                                                                  Volete condividere con
                                                                                                                     altre persone il sorgente
•	 Il componente di base, che si chiama “Screen1”,                                                                   delle vostre applicazio-
                                                                                                                     ni realizzate con l’App
   rappresenta la finestra principale dell’applica-                                                                  Inventor? Andate nella
   zione. Al suo interno ci sono tutti i componen-                                                                   lista dei progetti, selezio-
   ti trascinati nella schermata (nel nostro caso                                                                    nate uno, quindi dalla lista
   saranno “Image1”, “Button1” e “Sound1”).                                                                          “More actions” selezio-
   Selezionando uno dei componenti è possibi-            Fig. 8: L’anteprima dell’interfaccia realizzata
                                                                                                                     nate la voce “Download
                                                                                                                     Source”. Scaricherete così
   le rinominarlo (tasto “Rename”) o eliminarlo                                                                      un archivio ZIP che contie-
   definitivamente dalla schermata (“Delete”).                                                                       ne il progetto selezionato.
                                                         motore venga effettivamente riprodotto. Ci manca,           Un’altra persona potrà
•	 Properties.   Contiene gli strumenti utili per        insomma, quello che è il cuore di ogni applicazio-          importarlo nel suo account
   modificare le proprietà di ciascun elemen-            ne: la logica, cioè la sequenza di indicazioni di tipo      su App Inventor, selezio-
                                                                                                                     nando questa volta la voce
   to dell’applicazione. Per modificare l’aspetto        causa-effetto che sono il cuore di ogni applicazione.       “Upload Source”.
   di un componente è anzitutto necessario sele-         Descrivere una logica è ciò per cui i linguaggi di          In questa maniera potrà
   zionarlo nell’anteprima o dall’elenco presen-         programmazione sono nati. Il codice serve proprio           anche lui lavorare sul
   te nell’area “Components”. Fatto ciò, la scheda       per gestire il legame tra le cause e gli effetti, ed        vostro progetto.
   “Properties” riporterà tutti i dettagli del compo-    infatti ogni codice suona sempre come «se accade
   nente selezionato che è possibile modificare.         questo, allora fai quest’altro». Come è possibile,
   Quali siano le proprietà modificabi-                  quindi, stabilire queste sequenze di azioni di questo
   li dipende dalla natura del componente.               genere se App Inventor, come si è detto in apertura,
                                                         non richiede la conoscenza di un linguaggio di pro-
•	 Media. Qui vengono riportati tutti i file multime-    grammazione?
   diali (immagini, audio, video) necessari all’appli-   La risposta è: attraverso il Blocks Editor. Si tratta di
   cazione. Con il tasto “Add” è possibile avviare la    un editor visuale che sostituisce completamente la
   procedura di upload di un nuovo file.                 necessità di scrivere codice, e lo fa attraverso delle
                                                         rappresentazioni grafiche dei flussi causa-effetto.
Utilizziamo questi strumenti. Per prima cosa, usia-      Spiegarlo è molto più difficile che provarlo, andia-
mo l’area “Media” per caricare l’immagine e l’audio      mo dunque a sperimentarlo in prima persona.
di cui si è detto in precedenza.                         In alto a destra, l’App Inventor presenta il tasto
Andiamo poi su “Components”. Selezioniamo                “Open the Blocks Editor”. Premiamolo.
“Screen1”, che corrisponde alla finestra principa-       Il Blocks Editor è un applicativo esterno realizzato
le dell’applicazione, e modifichiamo alcune sue          in Java. Premendo sul tasto, il software sarà sca-
caratteristiche nell’area “Properties”. Cambiamo il      ricato ed eseguito. Per questo è molto probabile
colore di sfondo impostandolo su nero, e modifi-         che vi venga richiesto il consenso per l’esecuzio-
chiamo il titolo della finestra in modo che diventi      ne. Naturalmente bisogna acconsentire. Alla prima
“Automobile”.                                            esecuzione, inoltre, il Blocks Editor vi chiederà pro-
Passiamo ora a “Image1”. Impostiamo l’immagine           babilmente di digitare il percorso del comando adb,
da mostrare, alterando la proprietà “Picture”.           che è una delle utilità installate in precedenza con il
Associamogli l’immagine dell’automobile caricata         pacchetto App Inventor Setup Software, e che serve
poco prima nella sezione “Media”. Modifichiamo           per connettersi all’emulatore o ad un dispositivo
anche le proprietà del componente “Button1”.             reale. Andate quindi sul vostro disco a trovare il per-
In particolare, cambiamo il testo contenuto al suo       corso del comando adb.exe (Windows) o adb (Linux
interno, impostando la proprietà “Text” sul valo-        e Mac). Fornite tale percorso in maniera completa,
re “Metti in moto”. Finiamo modificando anche            ad esempio (Windows):



   84
h ttp :/ / www. i o p r o g r a m m o. it                                                                           2011 / 15
                                                                                                            Gennaio And roi d pr o g r am m in g
                                         Applicazioni Inventor
    Applicazioni Android senza scrivere codice con AppAndroid senza scrivere codice con App Inventor
              COVER STORY                                              Android programming


                                   C:\Program Files\AppInventor\commands-for-                 gue il suono contenuto nel componente “Sound1”.
                                                                        Appinventor\adb.exe   I blocchi set, invece, cambiano il valore di una pro-
                                                                                              prietà di un componente, ad esempio «set Image1.
                                   Una volta avviato, il Blocks Editor si presenta come       Picture to» cambia l’immagine mostrata dal com-
                                   in Fig.9                                                   ponente “Picture1”.
                                                                                              I blocchi set vanno collegati ad un’altra categoria di
                                                                                              blocchi, che fornisce il nuovo valore da impostare.
                                                                                              Questo valore può essere letto dalle proprietà di un
                                                                                              altro componente (quarto tipo di blocco in figura),
                                                                                              oppure specificato in altro modo attraverso una
                                                                                              delle altre caratteristiche messe a disposizione dal
                                                                                              Blocks Editor (provate ad esplorare le categorie di
                                   Fig. 9: Il Blocks Editor, cioè lo strumento per definire   blocchi messe a disposizione nella linguetta “Built-
                                   la logica di funzionamento dell’applicazione               in”). Facciamo ora in modo che alla pressione del
                                                                                              tasto “Button1” il suono del componente “Sound1”
                                                                                              venga riprodotto.
               NOTA                All’interno del Blocks Editor possiamo ritrovare           Trasciniamo allora il blocco «when Button1.Click
                                   tutti i componenti che abbiamo inserito all’interno        do» nell’area di lavoro. Colleghiamolo quindi con il
    ESPORTARE APK                  dell’applicazione. Sono nella scheda corrisponden-         blocco «call Sound1.Play», come mostrato in Fig.12.
           La forma finale per     te alla linguetta “My Blocks”.                             Proviamo a fare di più, aggiungendo una seconda
        la distribuzione delle                                                                conseguenza alla pressione del bottone. Facciamo
         applicazioni Android
 completate consiste in un                                                                    che, dopo aver avviato la riproduzione di “Sound1”,
   file con estensione .apk.                                                                  il testo di “Button1” cambi da “Metti in moto” a
      Avendo a disposizione                                                                   “Vroooooam!”.
      un file APK è possibile                                                                 È molto semplice farlo: aggiungete il blocco «set
   distribuire l’applicazione                                                                 Button1.Text to» all’evento Button1.Click. Il nuovo
     sul market o attraverso
    altri canali. Per ottenere                                                                testo può essere specificato usando uno dei blocchi
           l’APK di una vostra
           applicazione ormai
completa, aprite il progetto
       corrispondete su App
Inventor e dalla schermata
  di lavoro principale aprite
       l’elenco “Package for
       Phone” e scegliete la       Fig. 10: I blocchi disponibili per il componente
     voce “Download to this        “Button1”
    Computer”. Potrete così
          scaricare il file .apk
      che contiene la vostra
           applicazione finita.    Tocchiamo la voce “Button 1”: apparirà un elenco
                                   pieno di blocchi che corrispondono ad eventi e
                                   proprietà del componente. È subito evidente che            Fig. 12: La logica della nostra prima applicazione
                                   i blocchi mostrati sono raggruppabili in categorie
                                   differenti.
                                   I blocchi verdi, che chiameremo eventi, sono tutti         del gruppo “Built-in”.
                                   del tipo «when … do», ad esempio «when Button1.            Trascinate il blocco text nell’area ed agganciatelo a
                                   Click do», che significa «quando viene cliccato            «set Button1.Text to».
                                   Button1 fai questo». Al loro interno, infatti, c’è         A questo punto, cliccando sul nuovo blocco, potrete
                                   spazio per inserire un blocco di tipo azione, come         digitare il testo da impostare. Provate ad esempio
                                   quelli del tipo «call …» e «set … to».                     digitando “Vroooooam!”, oppure la variante che
                                   I blocchi call eseguono un’azione che il componen-         preferite.
                                   te può svolgere, ad esempio «call Sound1.Play» ese-




                                                                                              Fig. 13: Ora sono state impostate due conseguenze
                                   Fig. 11: Differenti tipologie di blocchi a confronto       al clic del tasto “Button1”



        16 / Gennaio 2011
A n d ro id p r o g r a m m ing                                                                                                                       85
                                                                                                                          h ttp ://www.io pr o g r a m m o .i t
     Applicazioni Android senza scrivere codice con App Inventor scrivere codice STORY Inventor
              Android programming           Applicazioni Android senza  COVER con App


ESEGUIRE                                                  più, potrà stabilire il colore del gesso virtuale: bian-
L’APPLICAZIONE                                            co, giallo o rosso. Per completare l’opera, mettiamo
Scommetto che non vedere l’ora di provare l’appli-        a disposizione anche un tasto che funzioni come
cazione che abbiamo appena realizzato. Possiamo           un cancellino, ripulendo completamente la super-
farlo con l’emulatore o con un dispositivo reale.         ficie dello schermo-lavagna. Torniamo alla lista dei
Per utilizzare un dispositivo reale è necessario col-     progetti di App Inventor (link “My Projects”). Da
legarlo al computer via USB, non prima di aver            qui creiamo un nuovo progetto, che chiameremo
installato gli eventuali driver forniti dal produttore.   “lavagna”. Costruiamo quindi un’interfaccia come
                                                          quella mostrata in Fig.15. Per realizzare tale inter-
                                                          faccia, i passi da seguire sono:
                                                          1. Personalizziamo “Screen1”, cambiando il titolo
                                                             della finestra in “Lavagna” e cambiando in nero il
                                                             colore dello sfondo.
                                                          2. Trasciniamo dalla palette un componente
                                                             “HorizontalArrangement”, che è parte dell’elen-
                                                             co “Screen Arrangement”. Questo componente
                                                             permette di disporre in sequenza orizzontale una
Fig. 14: Il tasto “Connect to phone” permette l’esecu-       serie di altri componenti.
zione dell’applicazione su un dispositivo reale o su un   3. Dentro l’elemento “HorizontalArrangement”                             NOTA
emulatore
                                                             appena disposto, inseriamo una serie di quattro
                                                             componenti “Button”.                                     PUBBLICARE
                                                          4. Personalizziamo i bottoni. Cambiamo anzitutto            SUL MARKET
Per usare l’emulatore, invece, è sufficiente lanciare        i loro nomi da “Button1”, “Button2”, “Button3”           Avete realizzato un’ap-
il comando run-emulator dimostrato in precedenza             e “Button4” a “ButtonBianco”, “ButtonGiallo”,            plicazione pronta per
e aspettare che il sistema emulato venga caricato.           “ButtonRosso” e “ButtonPulisci”. Cambiamo                il mondo reale? Volete
                                                                                                                      distribuirla attraverso l’An-
Dall’interno del Blocks Editor, in alto, azionate il         il testo dei bottoni in modo che sia: “Bianco”,          droid Market di Google?
tasto “Connect to phone”.                                    “Giallo”, “Rosso” e “Pulisci”. Cambiamo inoltre          Connettetevi al seguente
Attendete qualche istante: il dispositivo (reale o           l’aspetto dei pulsanti: mettiamo su nero il colore       indirizzo:
emulato che sia) sarà contattato dall’App Inventor,          di sfondo di tutti e quattro i bottoni, aumentiamo       http://market.android.com/
e l’applicazione sarà scaricata ed eseguita al suo           le dimensioni del testo (valore 20), impostiamo          publish
interno.                                                     l’uso del grassetto e cambiamo il colore del testo       Attenzione però al fatto
                                                             in modo che ogni bottone esponga quello più              che, per iscriversi al mar-
                                                             appropriato. Mettiamo infine in corsivo la scritta       ket e pubblicare le proprie
                                                                                                                      applicazioni, è necessario
                                                             “Pulisci” sul quarto bottone.                            pagare 25 dollari con una
PROGETTO LAVAGNA                                          5. Trasciniamo dalla palette un componente di tipo          carta di credito.
Realizziamo un secondo progetto con App Inventor.            “Canvas”. Posizioniamolo subito sotto l’elemento
Cimentiamoci con qualcosa di leggermente più                 “HorizontalArrangement” disposto in preceden-
complicato (ma, come vedremo, sempre semplicis-              za. I componenti di tipo “Canvas” permettono di
simo). Sfruttiamo il touchscreen del nostro dispo-           tracciare linee liberamente sullo schermo: pro-
sitivo Android, realizzando un’applicazione che              prio quello che ci serve! Maneggiamo le proprietà
funzioni un po’ come una lavagna. L’utente, con il           dell’oggetto “Canvas”: mettiamo lo sfondo sul
dito, potrà tracciare linee e segni sullo schermo. In        colore nero ed il colore di disegno (“PaintColor”)
                                                             impostiamolo sul bianco. Infine aggiustiamo
                                                             le dimensioni dell’elemento: per la larghezza
                                                             scegliamo lo speciale valore “fill_parent” (rende
                                                             l’elemento largo quanto tutto lo schermo) e per
                                                             l’altezza digitiamo il valore preciso di 370 pixel.
                                                             Accertiamoci infine che il nome del componente
                                                             sia proprio “Canvas1”, come dovrebbe essere in
                                                             maniera predefinita.

                                                          Fatta l’interfaccia, muoviamoci sul Blocks Editor
                                                          per “programmare” la logica necessaria all’applica-
                                                          zione. Prevediamo cinque differenti eventi:

                                                          1. Al clic sul bottone “Bianco” dobbiamo cambiare
                                                             il “PaintColor” di “Canvas1”, impostandolo sul
Fig. 15: L’applicazione in esecuzione sull’emulatore         bianco.



   86
h ttp :/ / www. i o p r o g r a m m o. it                                                                            2011 / 17
                                                                                                             Gennaio And roi d pr o g r am m in g
                                         Applicazioni Inventor
    Applicazioni Android senza scrivere codice con AppAndroid senza scrivere codice con App Inventor
              COVER STORY                                              Android programming


                                   2. Al clic sul bottone “Giallo” dobbiamo cambiare
                                      il “PaintColor” di “Canvas1”, impostandolo sul
                                      giallo.
                                   3. Al clic sul bottone “Rosso” dobbiamo cambiare
                                      il “PaintColor” di “Canvas1”, impostandolo sul
                                      rosso.
                                   4. Al clic sul bottone “Pulisci” dobbiamo ripulire il
                                      contenuto di “Canvas1”.
                                   5. In qualche maniera, quando l’utente trascina il
                                      dito all’interno di “Canvas1”, dobbiamo far trac-
                                      ciare una linea del colore impostato.

                                   Vediamo, passo dopo passo, come realizza-
                                   re questi cinque punti. Cominciamo dal bottone                Fig. 17: La logica per tracciare una linea ad ogni movi-
                                   “ButtonBianco”. Trasciniamo sul campo il gestore              mento del dito sul componente “Canvas1”
                                   di evento «when ButtonBianco.Click do». Come
                                   conseguenza dell’azione incastriamo al suo interno
                                   il blocco «set Canvas1.PaintColor to». Il colore da           trascina il dito, l’evento riporterà le informazioni
                                   collegare a questo blocco possiamo sceglierlo dal             aggiuntive all’interno delle variabili agganciate. A
                                   gruppo “Colors” della sezione di blocchi “Built-              noi, in particolar modo, interessa sapere che prevX
                                   in”. Naturalmente, per “ButtonBianco”, scegliete              e prevY riporteranno le coordinate che aveva il
               L’AUTORE            il colore “white”. Fate lo stesso per “ButtonGiallo”          dito prima dell’evento, mentre currentX e curren-
                                   e “ButtonRosso”, usando i colori “yellow” e “red”.            tY riporteranno quelle raggiunte al termine del
Carlo Pelliccia lavora presso      Al componente “ButtonPulisci”, invece, deve essere            movimento. Sfruttando questa informazione pos-
    4IT (www.4it.it), dove si      associata un’azione differente. Il blocco da incastra-        siamo allora inserire la conseguenza dell’evento,
occupa di analisi e sviluppo       re è tra quelli di “Canvas1”, e per l’esattezza è l’azio-     trascinando al suo interno un blocco «call Canvas1.
     di applicazioni server e
   mobili. Nella sua carriera      ne «call Canvas1.Clear» (cioè «ripulisci Canvas1»).           DrawLine».Per disegnare una linea, come spie-
        di technical writer ha     Ora dobbiamo fare in modo che trascinando il dito             gato prima, ci vogliono le quattro coordinate che
 pubblicato cinque manuali         su Canvas1 vengano disegnate delle linee. L’evento            indicano da dove la linea parte (x1 e y1) e dove la
  ed oltre duecento articoli,      da gestire corrisponde al blocco «when Canvas1.               linea finisce (x2 e y2), ed infatti il blocco che abbia-
   molti dei quali proprio tra     Dragged do». Trasciniamolo sull’area di lavoro del            mo aggiunto dispone degli agganci necessari per
 le pagine di ioProgrammo.
        Il suo sito, che ospita    Blocks Editor. Questo blocco di gestione evento,              queste quattro informazioni. Non dobbiamo far
       anche diversi progetti      come avrete sicuramente notato, è un po’ più com-             altro che collegare ciascuno di questi tasselli con la
 Open Source, è disponibile        plesso di quelli utilizzati per gestire i clic sui bottoni.   corrispettiva variabile. I blocchi utili per compiere
  all’indirizzo www.sauron-        L’evento di clic, infatti, è molto semplice e non ha          questa operazione sono presenti nella voce “My
                     software.it   argomenti o varianti sul tema. Muovere il dito sullo          Definitions”. Trascinate nell’are di lavoro i blocchi
                                   schermo, invece, è un’azione più complessa.                   «value prevX», «value prevY», «value currentX» e
                                   In questo caso non basta sapere che il dito si è              «value currentY», agganciandoli, rispettivamente, ai
                                   mosso: bisogna anchesapere da dove è partito e                tasselli x1, y1, x2 e y2.
                                   fin dove è arrivato. Proprio per riportare questo
                                   genere di informazioni l’evento «when Canvas1.
                                   Dragged do» aggancia automaticamente i blocchi
                                   di tipo «name …». Questi blocchi realizzano ciò che,          CONCLUSIONI
                                   in gergo, è chiamata una variabile. Quando l’utente           Attraverso una coppia di esempi pratici abbiamo
                                                                                                 esplorato le principali possibilità di App Inventor,
                                                                                                 La piattaforma, naturalmente, dispone di ulteriori
                                                                                                 caratteristiche che permettono di spingersi più in
                                                                                                 là nella realizzazione di applicazioni complesse
                                                                                                 ed adatte al mondo reale. Anche gli aspetti più
                                                                                                 avanzati di App Inventor, ad ogni modo, sono
                                                                                                 semplici da apprendere ed impiegare. Potete a
                                                                                                 questo punto approfondire da voi, sperimentando
                                                                                                 i tanti componenti a disposizione nella palette
                                                                                                 sulla sinistra e, se masticate un po’ di inglese,
                                                                                                 seguendo alcuni tra i tanti tutorial a disposizione
                                                                                                 nella sezione “Learn”.

Fig. 16: La logica per la gestione dei quattro pulsanti                                                                                      Carlo Pelliccia


        18 / Gennaio 2011
A n d ro id p r o g r a m m ing                                                                                                                          87
                                                                                                                             h ttp ://www.io pr o g r a m m o .i t
                                                       API e per interagire con Twitter da Android
                             COVER programming API e librerie librerie per interagire con Twitter da Android
                             Android STORY�




PORTA TWITTER
SU GOOGLE ANDROID
IN QUESTO ARTICOLO VEDREMO COME SVILUPPARE UN’APPLICAZIONE PER ANDROID,
CAPACE DI DIALOGARE CON IL SERVIZIO DI SOCIAL NETWORKING TWITTER. A TAL SCOPO
MOSTREREMO COME UTILIZZARE LA LIBRERIA TWITTER4J




                                            C
                                                     osa stai facendo? Basta rispondere a que-      1 – molte testate di giornali, o di news in genera-
                                                     sta semplicissima domanda per comin-             le, (specialmente quelle americane e inglesi)
                                                     ciare a utilizzare uno dei servizi di social     usano Twitter come mezzo per diffondere le
                                            network che sta esponenzialmente aumentando               ultime notizie. Avendo a disposizione sola-
                                            le registrazioni e sta prepotentemente imponen-           mente 140 caratteri compongono un Tweet di
                                            dosi come una delle più importanti piattaforme            pochissime parole seguito da un link all'artico-
                                            in questo campo. Una delle tante definizioni              lo vero e proprio. Naturalmente un URL può
                                            possibili per twitter ce la dà Wikipedia: “Twitter è      essere relativamente lungo, soprattutto se
                                            un servizio di social network e microblogging che         paragonato alla limitata disponibilità di testo
    ❑ CD ❑ WEB
    twitterAndroid.zip                      fornisce agli utenti una pagina personale aggior-         di Twitter. Per questo si utilizza solitamente
                                            nabile tramite messaggi di testo con una lunghez-         degli strumenti tipo TinyURL; questo è un ulte-
                     cdrom.ioprogrammo.it
                                            za massima di 140 caratteri.                              riore esempio di come possano nascere siner-
                                            Gli aggiornamenti possono essere effettuati trami-        gie tra strumenti e servizi fra loro eterogenei.
                                            te il sito stesso, via SMS, con programmi di mes-       2 – una cosa che mancava a Twitter era proprio la
                                            saggistica istantanea, e-mail, oppure tramite             possibilità di ricercare tutti quei Tweet che ver-
                                            varie applicazioni basate sulle API di Twitter”.          tessero sullo stesso argomento. A tale lacuna
                                            Un concetto centrale nel funzionamento di                 sono stati gli stessi utenti a porre rimedio;
                                            Twitter è quello del following e dei follower.            infatti si è utilizzato il vecchio sistema dei tag.
                                            Il primo sta a indicare gli utenti che abbiamo            Quando si scrive qualcosa che si reputa essere
                                            deciso di seguire, ossia quegli utenti i cui tweet        di interesse generale, lo si termina con un tag
                                            (leggi nota) ci verranno notificati e andranno a          del tipo #topic, in questo modo, chiunque
                                            costituire la nostra friend timeline.                     voglia rispondere o dire qualcosa sull'argo-
                                            Simmetricamente a quanto appena detto, i fol-             mento, potrà farlo terminando a sua volta il
                                            lower costituiscono la lista di tutti quegli utenti       Tweet con il medesimo tag. Un esempio cele-
                                            che hanno deciso di seguirci. Naturalmente non            bre di questo tipo di utilizzo lo si è avuto a
                                            è assolutamente obbligatorio seguire uno dei              seguito delle elezioni in Iran, dove grazie a
                                            propri follower e viceversa. Uno dei punti di             Twitter e al tag #iranelection i manifestanti riu-
                                            forza di Twitter è proprio quello di consentire           scivano in qualche modo a tenere informata
                                            una lunghezza massima di 140 caratteri per ogni           l'opinione pubblica su ciò che stava accaden-
                                            post, anzi, per usare il gergo di Twitter, per ogni       do nel proprio paese.
                REQUISITI
                                            Tweet. Anche se a prima vista ciò possa apparire
                                            come una grossa limitazione rispetto ad altri           Adesso che abbiamo dato una brevissima intro-
Conoscenze richieste
   Java                                     strumenti come i normali blog o Facebook, gra-          duzione su cosa sia Twitter veniamo alla parte
                                            zie a ciò è possibile utilizzarlo con un gran nume-     maggiormente vicina ai nostri interessi, cioè lo
Software                                    ro di strumenti (PC, telefonini, palmari etc...) e di   sviluppo di applicazioni.
    Twitter4J, Eclipse.
    Android SDK                             applicazioni (vedi definizione di Wikipedia).
                                            Inoltre questa estrema necessità di sintesi nel
                                            comunicare ha fatto sì che l'utilizzo di questo
                                            servizio sia andato al di là di quello inizialmente     API PER I WEB SERVICE
Impegno
                                            previsto dagli stessi ideatori. Ne faremo breve-        DI TWITTER
¥                                           mente due esempi, ma se ne potrebbero elenca-           In un precedente articolo abbiamo già parlato
Tempo di realizzazione
                                            re molti altri, giusto per cercare di capire in che     dei Web Service REST-style, in particolare di cosa
                                            direzione si sta muovendo la Rete.                      siano, a cosa servano e come vadano utilizzati.

                                                                                                                             h t t p : / / w w w. i o p r o g r a m m o . i t
     G 22 /Ottobre 2009
     88                                                                                                                                  And roi d pr o g r am m in g
                    API e librerie per interagire con Twitter da
           API e librerie per interagire con Twitter da Android Android Android programming
                                                                           � COVER STORY


Fortunatamente, da qui a poco, andremo a utiliz-                       <source><a href="http://www.tweetdeck.com/">
zare delle API per Java che ci “nascondono” in                                                      TweetDeck</a></source>
gran parte i meccanismi di comunicazione che il                        <truncated>false</truncated>
web service di Twitter richiede. È però sempre                         <in_reply_to_status_id></in_reply_to_status_id>
bene sapere cosa stia “succedendo” all'interno
della libreria che utilizzeremo, soprattutto in                        <in_reply_to_user_id></in_reply_to_user_id>
visione del refactoring che sarà necessario effet-                     <favorited>false</favorited>
tuare sulla libreria stessa per realizzare il porting                  <in_reply_to_screen_name></in_reply_to_
sulla piattaforma Android.                                                                                      screen_name>
REST è un acronimo che sta per “Representational                       <user>
State Transfer” e, cosa ancora più importante, non                     <id>1401881</id>
è uno standard, bensì un An Architectural Style.                        <name>Doug Williams</name>
Senza addentrarci in discussioni più filosofiche                        <screen_name>dougw</screen_name>                                     NOTA
che di ingegneria del software facciamo subito                          <location>San Francisco, CA</location>
un esempio mirato:                                                      <description>Twitter API Support. Internet, greed,         CURIOSITÀ
                                                                                                                                   Il nome "Twitter",
                                                                                       users, dougw and opportunities are my
                                                                                                                                   corrispondente sonoro
                                                                                                      passions.</description>      della parola tweeter, deriva
                                                                       <profile_image_url>http://s3.amazonaws.com/                 dal verbo inglese to tweet
                                                                        twitter_production/profile_images/59648642/avatar_         che significa "cinguettare".
                                                                                               normal.png</profile_image_url>      Tweet è anche il termine
                                                                                                                                   tecnico degli
                                                                        <url>http://www.igudo.com</url>
                                                                                                                                   aggiornamenti del servizio
                                                                        <protected>false</protected>
                                                                        <followers_count>1027</followers_count>
                                                                       <profile_background_color>9ae4e8</profile_backgro
                                                                                                                    und_color>
                                                                        <profile_text_color>000000</profile_text_color>
Fig. 1: Formato di una request per ottenere la friends-                 <profile_link_color>0000ff</profile_link_color>
timeline dello user specificato nella fase di autentica-               <profile_sidebar_fill_color>e0ff92</profile_sidebar_
zione
                                                                                                                     fill_color>
                                                                       <profile_sidebar_border_color>87bc44</profile_side
                                                                                                            bar_border_color>
in Fig. 1 sono riportati i parametri necessari per                      <friends_count>293</friends_count>
ottenere la friends-timeline dello user specifica-                      <created_at>Sun Mar 18 06:42:26 +0000
to nella fase di autenticazione. Tralasciando per                                                          2007</created_at>
ora la parte che concerne l'autenticazione,                             <favourites_count>0</favourites_count>
vediamo come funziona la comunicazione tra un                           <utc_offset>-18000</utc_offset>
generico client e il web service.                                       <time_zone>Eastern Time (US &
In base a quanto riportato in Fig.1 (che non è                                                          Canada)</time_zone>
altro che la documentazione delle REST API di
Twitter consultabile all'indirizzo http://apiwiki.                     <profile_background_image_url>http://s3.amazonaw
twitter.com/Twitter-REST-API-Method%3A-statuses-                        s.com/twitter_production/profile_background_images
friends_timeline) per ottenere gli ultimi 25 tweet                     /2752608/twitter_bg_grass.jpg</profile_background_
della nostra friends-timeline codificati in forma-                                                                 image_url>
to XML sarà necessario comporre un URL del
tipo http://twitter.com/statuses/friendstimeline.xml?                  <profile_background_tile>false</profile_background_tile>
count=25                                                                <statuses_count>3390</statuses_count>
A questo punto il web service risponderà come                           <notifications>false</notifications>
segue:                                                                  <following>false</following>
                                                                        <verified>true</verified>
<?xml version="1.0" encoding="UTF-8"?>                                 </user>
<statuses>                                                                 </status>
       <status>                                                            ... truncated ...
<created_at>Tue Apr 07 22:52:51 +0000                                  </statuses>
                                                   2009</created_at>
<id>1472669360</id>                                                    Per motivi di spazio, non riportiamo tutta la
<text>At least I can get your humor through tweets.                    risposta per intero. Ad ogni modo i tag status
           RT @abdur: I don't mean this in a bad way, but              all'interno di statuses si ripetono con la medesi-
            genetically speaking your a cul-de-sac.</text>             ma struttura.

h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                              Ottobre 2009/ 23 G
                                                                                                                                            89
                                           API e per interagire con Twitter da Android
                 COVER programming API e librerie librerie per interagire con Twitter da Android
                 Android STORY�


                             Ora, se dovessimo fare tutto da zero dovremmo
                             fare delle request via http, aprire un socket per
                             ottenere lo stream in lettura; una volta ottenuto
                             andrebbe letto e parsato a seconda del formato
                             specificato (xml, json, rss, atom) al momento
                             della request.
                             Fortunatamente esistono diverse librerie per
                             Java che si fanno già carico di tutto questo lavoro
                             e ci mettono a disposizione già delle classi ben
                             formate. Abbiamo comunque ritenuto significa-
                             tivo riportare un esempio di risposta in XML,
                             perché le gerarchie e la composizione delle clas-
                             si ricalca proprio la struttura dello XML stesso,        Fig. 2: Insieme delle librerie necessarie al progetto
                             perciò avere un'idea di come esso sia strutturato        Twitter
                             significa riuscire già a utilizzare la libreria in
                             maniera corretta.
         NOTA                                                                         public static void main(String[] args) throws
                                                                                                                                     TwitterException
              TINYURL                                                                 {
TinyURL è un sito web che
diminuisce la lunghezza di
                             LA LIBRERIA TWITTER4J                                     Twitter twitter = new

       un URL per poterla    La libreria Twitter4j è reperibile all'indirizzo                               Twitter("userName","password");
comunicare facilmente via    http://yusuke.homeip.net/twitter4j/en/index.html ed è     Paging pag = new Paging();
email o Instant Messaging    una delle API Java per Twitter maggiormente dif-          pag.setCount(25);
                             fuse. Nel sito citato poc'anzi trovate elencate           List<Status> statusList =
                             tutte le caratteristiche di tale libreria. In partico-                            twitter.getFriendsTimeline(pag);
                             lare a noi interessa che sia scritta al 100% in Java      for (Status status : statusList)
                             e che sia compatibile con Android. In realtà que-         {
                             sta ultima feature non è completamente esatta,                System.out.println(status.getId() +" - "+
                             ma ci occuperemo di ciò a tempo debito.                                                               status.getText());
                             Cominciamo, invece, a scrivere un po' di codice.          }
                             Sia per la stesura di questo articolo, sia del pros-     }
                             simo, è stato utilizzato come ambiente di svilup-
                             po Eclipse. A ogni modo, chiunque abbia un pro-          Per prima cosa è stato istanziato un oggetto della
                             prio IDE preferito diverso da Eclipse, può               classe Twitter al cui costruttore abbiamo passato
                             comunque applicare delle procedure simili a              il nostro user-name e la nostra password.
                             quelle che andremo a descrivere.                         Quando viene creato tale oggetto, si stabilisce già
                             Scaricate lo zip che trovate sul sito sopra citato       una connessione verso il web service e si occupa
                             (la versione 2.0.8 è l'ultima al momento della ste-      anche dell'autenticazione.
                             sura dell'articolo). Create poi un nuovo progetto        Subito dopo abbiamo creato un oggetto Paging;
                             che io ho chiamato Twitter. Per adesso non               possiamo considerare tale classe in maniera
                             siamo interessati ai sorgenti, perciò creiamo una        equivalente a un cursore nei database. I metodi
                             sotto-directory sulla root del progetto che chia-        messi a disposizione da tale classe sono diversi;
                             miamo lib e copiamo poi tutti i jar contenuti            per adesso ci possiamo accontentare di imposta-
                             nella directory lib dello zip nella nostra directory     re semplicemente il numero di tweet che voglia-
                             appena creata. Copiamo inoltre anche il file twit-       mo ci vengano restituiti.
                             ter4j-2.0.8.jar sempre nella stessa directory. A         L'invocazione del metodo getFriendsTimeline,
                             questo punto andiamo sulle proprietà del pro-            che prende come argomento proprio l'oggetto
                             getto (cliccando con il tasto destro sul progetto e      paging, restituisce una lista di oggetti status.
                             selezionando Properties...) e selezioniamo la            Avrete certamente notato come la struttura delle
                             voce Java build path e poi il tab Libraries.             classi ricalchi perfettamente quella dello XML
                             Premendo il pulsante Add Jars... selezionate tutti       precedentemente riportato: infatti, dentro il tag
                             i jar che abbiamo precedentemente copiato nella          <statuses> (che corrisponde alla nostra lista di
                             directory lib. Una volta fatto tutto ciò, vi dovreste    oggetti status) si susseguono una serie di tag
                             trovare in una situazione analoga a quella ripor-        <status> figli. A sua volta tale tag ha un serie
                             tata in Fig. 2. È quindi tutto pronto per effettuare     diversificata di sotto-figli, per ognuno di essi la
                             i primi test con la libreria Twitter4j. Vediamo          classe Status mette a disposizione dei relativi
                             innanzitutto come ottenere gli ultimi 25 tweet,          metodi getters che restituiscono un dato già
                             così come nell'esempio precedente:                       tipizzato. Nel nostro esempio abbiamo deciso di


  G 24 /Ottobre 2009
                                                                                                                  h t t p : / / w w w. i o p r o g r a m m o . i t
  90                                                                                                                          And roi d pr o g r am m in g
                    API e librerie per interagire con Twitter da
           API e librerie per interagire con Twitter da Android Android Android programming
                                                                           � COVER STORY


stampare l'id, lo user e il testo di ogni status della                      piedi un ambiente che ci permetta di sviluppare
FriendsTimeline. Con il mio account ho ottene-                              e debugare la nostra applicazione. Dopo aver
nuto il seguente output sulla console:                                      installato e scaricato Android, una delle parti più
                                                                            importanti è quella della creazione del Virtual
2691267627 - TIME.com - For #ff, add @time_live.                            Device. Infatti è proprio grazie a questo punto
                Starting Monday, it's the best way for you to               che saremo in grado di emulare un generico
     communicate 1-on-1 with our newsroom. And we'll                        dispositivo sul nostro PC. Per fare ciò basta lan-
                                                       follow you back!     ciare da prompt il comando Android create avd -
2691154798 - developerworks - Learn how to create                           -target 2 --name my_avd. La prima parte del
       drag-and-drop code that is modular, and easier to                    comando (create avd) indica che vogliamo creare
                      write and maintain > http://su.pr/6bXlqP              un nuovo Android Virtual Device, la seconda (--
2690818806 - Andrea Galeazzi - I'm watching rock &                          target 2) fa sì che tale device possa girare sull'e-
                                                   roll circus...amazing!   mulatore, mentre la terza (--name my_avd)
2690608685 - TIME.com - Why girls have BFFs and                             imposta semplicemente il nome del device che
              boys hang out in packs | http://su.pr/92EuL5                  andremo a creare. A questo punto, una volta lan-
2690262831 - developerworks - Parallel development                          ciato tale comando, vi verrà chiesto se volete
  for mere mortals - Step through Subversion version-                       creare un profilo hardware personalizzato; noi                    NOTA
                                      control > http://su.pr/2leWWm         possiamo tranquillamente accettare quello di
2689450274 - developerworks - Writing great code                            default e quindi premere invio. Ora il nostro           SMARTPHONE
          with FileNet P8 APIs - Reliable-Scalable-Highly-                  device è pronto per essere fatto girare sotto           ANDROID
                                                                                                                                    HTC è stata la prima
 Available content management > http://su.pr/19PsCq                         l'emulatore.
                                                                                                                                    azienda al mondo a
…....                                                                                                                               mettere in vendita uno
                                                                                                                                    smartphone con installato il
Vediamo invece come inviare i nostri tweet uti-                                                                                     sistema operativo Android.
lizzando la libreria Twitter4j: in questo caso la                           L'AMBIENTE                                              Dopo aver lanciato sul
                                                                                                                                    mercato i vari HTC Dream,
procedura è anche più semplice di quella vista                              DI SVILUPPO                                             HTC Magic e l’ultimissimo
poco fa. Infatti, una volta istanziato l'oggetto                            Quando parliamo di programmazione in Java,              HTC Hero, ora l’azienda di
twitter che si occupa della connessione e dell'au-                          indipendentemente da ciò che stiamo svilup-             Taiwan vorrebbe arrivare
tenticazione, basta invocare il metodo                                      pando, difficilmente possiamo fare a meno di            sul mercato con un nuovo
updateStatus come segue:                                                    Eclipse ed anche questo caso non fa eccezione.          smartphone Android: l’HTC
                                                                                                                                    Click.
                                                                            Per sviluppare sulla piattaforma Android con
Status status = twitter.updateStatus("That's an                             Eclipse è necessario installare il relativo plug-in e
                 example about how to tweet by Twitter4j");                 configurarlo opportunamente.
                                  System.out.println("Successfully          Utilizzando l'ultima versione di Eclipse al
     updated the status to [" + status.getText() + "].");                   momento, Galileo, basta che andiate su Help
                                                                            Install New Software e clicchiate sul bottone
Tale codice produce il seguente output:                                     Add. Inserite poi nel campo Location https://dl-
                                                                            ssl.google.com/android/eclipse/ e scegliete il
Successfully updated the status to [That's an                               nome che preferite nel campo Name, premete
                    example about how to tweet by Twitter4j]                poi OK. Così facendo dovrebbe apparire una
                                                                            check box con il nome "Developer Tools", sele-
                                                                            zionatela e premete Next e poi Finish. Se tutto
                                                                            procede correttamente alla fine vi verrà chiesto
ANDROID                                                                     di riavviare Eclipse. Una volta riavviato andate
E IL SUO EMULATORE                                                          su Window Preferences e selezionate Android
Potremmo continuare a esporre ulteriori funzio-                             sulla parte destra.
nalità della libreria Twitter4j, ma non dobbiamo                            Ciò che è necessario impostare è la location di
dimenticare che il nostro scopo è quello di                                 dove abbiamo posizionato l'SDK di Android
implementare un client di Twitter che giri sulla                            (nel nostro caso D:\Program Files (x86)\
piattaforma Android. È quindi opportuno, a que-                             android-sdk-windows-1.5_r2\).
sto punto, iniziare a introdurre i concetti base su                         Una volta selezionato correttamente il percor-
cui si fonda il sistema operativo di Google.                                so dovreste ritrovarvi in una situazione del
Android è una piattaforma per dispositivi mobili                            tutto simile a quella riportata in Fig. 4. Anche se
che include sistema operativo, middleware e                                 quest'ultima parte può risultare tediosa è fonda-
applicazioni di base. Maggiori informazioni,                                mentale che venga correttamente eseguita in
comunque, sono reperibili nel precedenti artico-                            modo tale da evitare che durante la fase di svi-
lo di questa cover story). Per essere quanto più                            luppo qualcosa non funzioni senza capirne il
pratici possibile, vediamo subito di mettere in                             motivo.


h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                              Ottobre 2009/ 25 G
                                                                                                                                            91
                                                API e per interagire con Twitter da Android
                      COVER programming API e librerie librerie per interagire con Twitter da Android
                      Android STORY�


                                                                                        tale classe sovrascrive il metodo onCreate come
                                                                                        segue:

                                                                                        public class HelloWord extends Activity { @Override
                                                                                            public void onCreate(Bundle savedInstanceState){
                                                                                               super.onCreate(savedInstanceState);
                                                                                               setContentView(R.layout.main); }
                                                                                        }


                                                                                        Tale metodo viene invocato non appena questa
                                                                                        attività viene creata. Purtroppo, in questo artico-
                                                                                        lo, non abbiamo sufficiente spazio per approfon-
                                    Fig. 4: Configurazione del plug-in per Android      dire cosa si intenda per attività né per parlare
                                                                                        della creazione dei layout, limitiamoci quindi a
                                                                                        scrivere il codice necessario per visualizzare la
                                                                                        scritta Hello Word sul display del nostro Virtual
                                    ANDROID, HELLO WORD!                                Device:
                                    Dopo tanta fatica possiamo finalmente far girare
                                    la nostra prima applicazione su Android e, come     package it.ioprogrammo;
                                    la “tradizione” ormai impone, anche noi non         import android.app.Activity;
                                    potevamo esimerci dal cominciare proprio con        import android.os.Bundle;
                                    un bel Hello Word! Per prima cosa andate su File    import android.widget.TextView;
                                    New Other.Android Project e compilate i seguenti    public class HelloWord extends Activity {
            L’AUTORE
                                    campi:                                              @Override
                                                                                        public void onCreate(Bundle savedInstanceState) {
       Laureato in ingegneria
             elettronica presso     Project name: Hello Word                                super.onCreate(savedInstanceState);
       l'università Politecnica     Application name: Hello, word                           TextView tv = new TextView(this);
delle Marche, lavora presso         Package name: it.ioprogrammo                            tv.setText("Hello, Android");
   il reparto R&D della Korg        Create Activity: HelloWord                              setContentView(tv); }
          S.p.A. Nei limiti della
         disponibilità di tempo     Min SDK Version: 3                                  }
          risponde all'indirizzo
  andrea.galeazzi@gmail.            Dentro il package it.ioprogrammo troverete così     Non abbiamo fatto altro che creare un oggetto
                   com              la classe HelloWord che deriva dalla classe         TextView che è in grado di visualizzare un testo e
                                    Activity, che è presente nel framework di Andriod   poi l'abbiamo “appiccicato” al display mediante
                                    e di cui parleremo più diffusamente nel prossimo    il metodo setContentView(tv); non ci resta che
                                    articolo. Per adesso limitiamoci a constatare che   avviare l'activity, per farlo, andate su Run
                                                                                        Configurations... selezionate la voce Android App
                                                                                        lication e cliccate sul tasto New.
                                                                                        Chiamiamo anche questa configurazione
                                                                                        HelloWord e selezioniamo il progetto HelloWord
                                                                                        premendo il tasto Browse. A questo punto pre-
                                                                                        mete Run e finalmente dovreste ottenere quanto
                                                                                        riportato in Fig. 4. Naturalmente d'ora in poi
                                                                                        possiamo avviare tale configurazione semplice-
                                                                                        mente premendo il tasto Run.




                                                                                        CONCLUSIONI
                                                                                        In questo articolo abbiamo presentato Twitter e
                                                                                        utilizzato le API Java Twitter4j per usufruire dei
                                                                                        servizi messi a disposizione. Nella seconda parte
                                                                                        abbiamo invece iniziato a presentare il nuovo OS
                                                                                        di Google. Nel prossimo metteremo assieme
                                                                                        questi due aspetti per realizzare il nostro client
                                                                                        Twitter su Android!

Fig. 4: Activity Hello Word in azione sul nostro emulatore Android
                                                                                                                                       Andrea Galeazzi

                                                                                                                    h t t p : / / w w w. i o p r o g r a m m o . i t
   G 26 /Ottobre 2009
   92                                                                                                                           And roi d pr o g r am m in g
                                           La classe Activity e             dell’interfaccia con
     La classe Activity e il disegno dell’interfaccia con Androidil disegnoAndroid programming Android
                      MOBILE �




UN CLIENT TWITTER
SU ANDROID
CONTINUIAMO E COMPLETIAMO IL NOSTRO PROGETTO PER IMPLEMENTARE UN CLIENT
                                                                                                                                               PARTE 2
TWITTER SULLA PIATTAFORMA ANDROID. L’OCCASIONE CI PERMETTERÀ DI APPROFONDIRE
MOLTI ASPETTI SUL FUNZIONAMENTO DEL SISTEMA OPERATIVO CREATO DA GOOGLE




                                           C
                                                   hi lavora nel campo del software ormai lo      public void onCreate(Bundle savedInstanceState) {
                                                   sa benissimo: le cose cambiano con una             super.onCreate(savedInstanceState);
                                                   velocità elevatissima, magari un fra-              TextView tv = new TextView(this);
                                           mework o una piattaforma che avevamo impara-               tv.setText("Hello, Android");
                                           to a conoscere e utilizzare meno di un anno fa, è          setContentView(tv);
                                           già parte della storia dell'informatica.               }
                                           In questo articolo proveremo a mettere assieme         }
                                           due grosse novità di quest'anno (benché entram-
    ❑ CD ❑ WEB                             be hanno avuto origine uno o due anni prima):          La prima cosa importante da notare è che la nostra
    twitterclient144.zip
                                           Twitter e Android.                                     classe eredita dalla classe Activity. Possiamo pensa-
                    cdrom.ioprogrammo.it
                                           Visto che nello scorso articolo abbiamo dedicato       re alla classe Activity (o meglio alla classe che la
                                           maggior spazio al funzionamento di Twitter, sia        estende) come una classe che funge da “entry
                                           come social network che come set di API, questa        point” per l'applicazione che vogliamo realizzare.
                                           volta ci occuperemo prima di Android descriven-        A mio avviso, quando si sviluppa un'applicazione
                                           do i suoi meccanismi di funzionamento e come           per Android, è molto semplice adottare questo tipo
                                           implementare un'applicazione che si colleghi a         di visione: Android è un host all'interno del quale
                                           Internet e sia interagibile per mezzo di un touch-     possono girare più Activity. Di conseguenza un'ac-
                                           screen.                                                tivity verrà “pilotata” da Android che gli comuni-
                                                                                                  cherà quando viene avviata, messa in pausa, riav-
                                                                                                  viata o distrutta. La Fig. 1 illustra i vari stati in cui
                                                                                                  un'activity può venirsi a trovare e anche in che
                                           CREARE APPLICAZIONI
                                           PER ANDROID
                                           Abbiamo già dedicato una parte dello scorso arti-
                                           colo alla discussione dell'installazione di un envi-
                                           ronment che ci permetta di sviluppare delle appli-
                                           cazioni in Java ed emularle su un virtual device di
                                           Android. Si rimanda quindi al precedente numero
                                           di ioProgrammo per la messa in piedi di tale
                                           ambiente; in questa sede ci limitiamo a ricordare
                                           che è necessario scaricare e installare lo SDK di
                                           Android, reperibile all'indirizzo http://developer.
                                           android.com/sdk/1.5r3/index.html ed è fortemente
               REQUISITI
                                           consigliato utilizzare anche il relativo plug-in per
 Conoscenze richieste
                                           Eclipse. Proprio al termine di quest'ultimo aveva-
    Java                                   mo iniziato a scrivere la nostra prima applicazione
                                           Hello World. Ripartiamo quindi da dove ci siamo
 Software                                  lasciati la volta scorsa. Benché il codice sia abba-
     Eclipse, Android SDK
     1.5                                   stanza semplice già contiene vari aspetti che meri-
                                           tano di essere approfonditi:
 Impegno

¥                                          public class HelloWord extends Activity {
Tempo di realizzazione                        /** Called when the activity is first created. */   Fig. 1: State Diagramm che illustra il Life Cycle
                                              @Override
                                                                                                  di un'activity


                                                                                                                                h t t p : / / w w w. i o p r o g r a m m o . i t
     G 62 / Novembre 2009
A n d ro id p r o g r a m m ing                                                                                                                                     93
        La classe Activity e il disegno dell’interfaccia con Android
                Android programming                                           � MOBILE
                                                La classe Activity e il disegno dell’interfaccia con Android


modo può arrivarci. Lo state diagramm in questio-         un'applicazione per Android senza aver conoscen-
ne è già abbastanza esplicativo di per sé, vale           za della gestione del life-cycle di un'activity.
comunque la pena spendere alcune parole al                Un altro “mattoncino fondamentale” è quello dello
riguardo. Come potete notare, appena viene crea-          sviluppo dell'interfaccia grafica. Nell'esempio pre-
ta un'activity su di essa, vengono anche invocati         cedente abbiamo semplicemente creato una
nell'ordine i seguenti metodi: onCreate, onStart e        textView tramite una new, scritto su di essa il testo
onResume. Al termine dell'invocazione di quest'ul-        "Hello, Android" e posta la textView sul display.
timo metodo possiamo dire che l'applicazione sta          Potete facilmente intuire che se il layuot si comin-
girando. In particolare, nel metodo onCreate, ven-        cia a complicare un po' diventerebbe veramente
gono tipicamente creati quei componenti grafici           difficoltoso creare delle GUI questo modo.
che andranno a costituire l'interfaccia grafica. Tale     Esiste però anche un altro modo per definire il
interfaccia viene poi infatti settata mediante il         layuot di un'applicazione, ed è tramite un file XML;
metodo setContentView. Quando e se un'activity            cominciamo quindi subito con l'analizzare come è
viene sospesa, solitamente perché ne viene avviata        strutturato quello che definisce il layuot della
un'altra, è invocato il metodo onPause. In questo         nostra applicazione:
punto è opportuno salvare, qualora ce ne fosse
bisogno, tutti i dati che costituiscono lo stato in cui   <?xml version="1.0" encoding="utf-8"?>
si trova l'activity.                                      <AbsoluteLayout android:id="@+id/widget38"
Una volta che quest'ultima è posta nello stato pau-                                android:layout_width="fill_parent"
sed, abbiamo tre possibili stati successivi in cui sarà          android:layout_height="fill_parent" xmlns:android=
consentito andare:Destroyed, Stopped, Running.                        "http://schemas.android.com/apk/res/android">
Sul primo stato c'è abbastanza poco da dire, l'ap-        <ListView android:id="@+id/list"
plicazione viene killata (ad esempio a seguito di         android:layout_width="319px" android:layout_height="356px"
una chiusura), e qui è necessario rilasciare tutte le            android:layout_x="1px"android:layout_y="0px">
risorse eventualmente allocate all'inizio, più preci-     </ListView>
sante nel metodo onDestroy. I restanti due casi           <EditText                                                                NOTA
sono invece quelli più interessanti.                        android:id="@+id/text" android:layout_width="259px"
Cerchiamo di comprendere come mai siamo obbli-            android:layout_height="50px"android:background="#ffffffff"    TOOL PER
gati a implementare un'applicazione che sia in             android:textSize="12sp" android:textColor="#ff666666"
                                                                                                                        DISEGNARE
grado di gestire il proprio stato corrente mediante           android:layout_x="1px" android:layout_y="383px">
                                                                                                                        L’INTERFACCIA
la ricezione delle callback da parte del sistema ope-     </EditText>
                                                                                                                        GRAFICA
                                                                                                                        In realtà scrivere il file XML
rativo, che ci informa su quale sarà il prossimo          <Button android:id="@+id/button"                              per la definizione della GUI
stato nel quale la nostra activity andrà a trovarsi.                             android:layout_width="wrap_content"    dall'inizio alla fine può
Dobbiamo infatti tenere a mente che Android è                  android:layout_height="52px" android:text="Send"         risultare un compito noioso
stato progettato per girare su piattaforme hardwa-           android:layout_x="260px" android:layout_y="383px">
                                                                                                                        ed alcune volte anche poco
                                                                                                                        praticabile. Esiste a tal
re limitate e ciò comporta un'oculata gestione delle      </Button>
                                                                                                                        proposito un tool RAD di
sue risorse, specialmente la memoria. Per questo          </AbsoluteLayout>                                             nome AnDroidDraw
motivo Android gestisce le varie Activity come uno                                                                      (http://www.droiddraw.or
stack. In testa si trova quella attualmente in primo      Un client per Twitter è concettualmente molto                 g/androiddraw.html) che
piano sul display; immediatamente dopo si troverà         semplice, deve solamente assolvere a due compiti:             permette di definire
                                                                                                                        un'interfaccia grafica in
la penultima Activity, quella che come già accenna-       mostrarci la nostra friends-timeline e permetterci            maniera visuale.
to prima, è stata messa in stato Paused. Tutte le         di inviare i nostri Tweet. Per fare ciò abbiamo quin-
altre sotto quest'ultima vengono messe nello stato        di bisogno di solo tre componenti:
stopped dopo la chiamata ad onStopped. Se poi
l'activity viene richiamata in primo piano, a secon-      1. Una ListView in cui visualizzare i vari Tweet della
da della memoria richiesta nei momenti preceden-             friends-timeline;
ti, possiamo ritrovarci in due situazioni differenti: o   2. Una TextView in cui inserire ciò che vogliamo
la memoria a disposizione era sufficiente e quindi           “tweetare”;
verrà invocato il metodo onRestart, che alla fine ci      3. Un bottone per inviare effettivamente quanto
riporterà nello stato di Running, oppure è stato             scritto nel controllo sopra citato.
necessario uccidere l'Activity e quindi ricominciare
tutto ripartendo da onCreate.                             In Fig. 2 potete vedere come si presenta grafica-
                                                          mente l'XML appena riportato.
                                                          Notiamo che come layout di root abbiamo scelto
                                                          un AbsoluteLayout all'interno del quale abbiamo
DEFINIRE UNA                                              posto i nostri controlli; gli attributi associati a que-
GUI SU ANDROID                                            st'ultimi sono talmente palesi che approfondire il
Sicuramente non è possibile tentare di scrivere           loro significato non sarebbe di alcuna utilità.

h t t p : / / w w w. i o p r o g r a m m o . i t
    94                                                                                                     Novembre 2009 d/pr o g r am m in g
                                                                                                                     And roi 63 G
                                         La classe Activity e              dell’interfaccia con
   La classe Activity e il disegno dell’interfaccia con Android il disegnoAndroid programming Android
                    MOBILE �


                                                                                                         public static final int refresh=0x7f020001;
                                                                                                     }
                                                                                                     public static final class id {
                                                                                                         public static final int button=0x7f050003;
                                                                                                         public static final int list=0x7f050001;
                                                                                                         public static final int text=0x7f050002;
                                                                                                         public static final int widget38=0x7f050000;
                                                                                                     }
                                                                                                     public static final class layout {
                                                                                                         public static final int main=0x7f030000;
                                                                                                     }
                                                                                                     public static final class string {
                                                                                                         public static final int app_name=0x7f040001;
                                   Fig. 2: Layuot dell'applicazione TwitterClient                        public static final int hello=0x7f040000;
                                                                                                     }
                                                                                                 }
                                   Ciò che invece è importante iniziare a notare è
                                   come settare il layout descritto nel file XML.                Tralasciando di descrivere nel dettaglio meccani-
                                   Veniamo quindi immediatamente a codice che                    smi interni, sia per motivi di spazio sia perché alla
                                   setta il layout sulla onCreate.                               fine tutto risulta trasparente dal lato dello sviluppa-
                                                                                                 tore, possiamo affermare che è possibile recupera-
                                   public class TwitterClient extends Activity implements        re la maggior parte delle risorse proprio attraverso
                                                                             OnClickListener {   tale file. Poco fa abbiamo visto come impostare il
                                    private EditText text = null;                                layout recuperando il suo id proprio dalla classe R.
                                    private Button btn = null;                                   Avrete di certo notato che, ad esempio, oltre alla
                                    private TwitterAdapter adapter = null;                       sotto classe layout, ne esiste un'altra chiamata id, i
                                    private Twitter twitter = null;                              cui membri hanno come nome proprio gli id speci-
             NOTA                   @Override                                                    ficati nel relativo attributo del file main.xml.
                                    public void onCreate(Bundle savedInstanceState) {            Ciò ci dà lo spunto per avanzare ulteriormente nel-
                TWITTER4J             super.onCreate(savedInstanceState);                        l'analisi del nostro codice. Rivediamo quindi per
        La libreria Twitter4j è       setContentView(R.layout.main);                             intero il metodo onCreate che avevamo preceden-
        reperibile all'indirizzo      ...                                                        temente troncato:
http://yusuke.homeip.net/t
 witter4j/en/index.html (è         Per adesso tralasciamo il fatto che la nostra appli-          @Override
          presente anche nel
      supporto CD-ROM che          cazione TwitterClient implementi anche l'interfac-             public void onCreate(Bundle savedInstanceState) {

accompagna la rivista) ed è        cia OnClickListener (ce ne occuperemo di qui a                    super.onCreate(savedInstanceState);
       una delle API Java per      poco). Ciò che adesso ci interessa analizzare è la                setContentView(R.layout.main);
       Twitter maggiormente        chiamata al metodio setContentView. Quando                        ListView lv = (ListView)findViewById(R.id.list);
       diffuse. Nel sito citato    create un nuovo progetto Android il plug-in di                    text = (EditText)findViewById(R.id.text);
   poc'anzi trovate elencate
    tutte le caratteristiche di    Eclipse (vedi articolo precedente) definisce già una              btn =(Button)findViewById(R.id.button);

tale libreria. In particolare a    struttura predefinita che, ad esempio, affianca alla              btn.setOnClickListener(this);
noi interessa che sia scritta      directory src, dove sono contenuti i sorgenti, un'al-             try {
  al 100% in Java e che sia        tra chiamata res contenente a sua volta altre tre                  twitter = new Twitter("name","password");
    compatibile con Android        sotto directory: drawable, layout e strings.                       adapter = new TwitterAdapter
                                   Senza addentrarci nei dettagli di ognuna di esse,                     (twitter,this,android.R.layout.simple_list_item_1);
                                   concentriamoci ad esempio sulla directory layout                   lv.setAdapter(adapter);
                                   dato che è quella che ci riguarda più da vicino.                  } catch (TwitterException e) {}
                                   Il file main.xml in essa contenuto è proprio quello           }
                                   riportato sopra. Il plug-in di Eclipse genera auto-
                                   maticamente una costante numerica per ogni                    Si ha ora la necessità di recuperare i componenti
                                   entità contenuta nella directory res:                         definiti nell'XML come classi Java. A differenza del
                                                                                                 primo esempio, Hello Android, in cui facevamo
                                   /* AUTO-GENERATED FILE. DO NOT MODIFY.                        esplicitamente delle new per i componenti che ci
                                   package it.galeazzi.andrea;                                   servivano, in questo caso dobbiamo utilizzare il
                                   public final class R {                                        metodo findViewById, che restituisce il componen-
                                      public static final class attr {}                          te a partire da un dato id, che, come al solito, ci
                                      public static final class drawable {                       viene fornito dalla classe R. Visto poi che tale meto-
                                            public static final int icon=0x7f020000;             do restituisce una generica View (classe base), è


    G 64 / Novembre 2009
                                                                                                                               h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                                                    95
        La classe Activity e il disegno dell’interfaccia con Android
                Android programming                                           � MOBILE
                                                La classe Activity e il disegno dell’interfaccia con Android


necessario effettuare un down-cast per ottenere                         return adapter.isEmpty();
effettivamente la classe specializzata voluta. Fate                    }
quindi attenzione a far coincidere il tipo indicato                    public boolean isEnabled(int position) {
dall'id con il down-cast che effettuate sul valore di                   return adapter.isEnabled(position);
ritorno del metodo findViewById.                                       }
                                                                       public void
                                                                           registerDataSetObserver(DataSetObserver observer) {
                                                                       adapter.registerDataSetObserver(observer);
UN ADAPTER DI TWITTER                                                  }
PER LA LISTVIEW                                                        public void unregisterDataSetObserver
Il pattern MVC è molto diffuso nelle librerie Java, e                                               (DataSetObserver observer) {
anche Android non fa eccezione in questo senso.                        adapter.unregisterDataSetObserver(observer);
In particolare una ListView va associata a un                          }
ListAdapter che sarà in grado di fornirle i dati da                    public void refresh() throws TwitterException {
visualizzare. Tornando nuovamente ai nostri scopi,                         adapter.clear();
i dati, che nello specifico sono gli ultimi tweet della                    for (Status status : twitter.getFriendsTimeline()) {
nostra friends-timeline, debbono essere recuperati                                      adapter.add(status.getUser().getName() + ":
tramite le API messe a disposizione dal web service                                                             "+status.getText());
di Twitter a cui ci collegheremo grazie alla libreria                  }
Twitter4j presentata nell'articolo precedente:                         }                                                                          NOTA

public class TwitterAdapter implements ListAdapter {                   Al costruttore tale classe riceve tre parametri: il
  private Twitter twitter;                                             primo è l'oggetto twitter che ci permette di colle-
                                                                                                                                       PATTERN MVC
                                                                                                                                       È un pattern architetturale
  private ArrayAdapter<String> adapter;                                garci al web service, mentre gli altri due vengono              molto diffuso nello sviluppo
  public TwitterAdapter(Twitter twitter,Context                        passati direttamente all'oggetto adapter. Inoltre, è            di interfacce grafiche di
                 context, int viewId) throws TwitterException {        stato aggiunto il metodo refresh, non previsto dal-             sistemi software object-
    super();                                                           l'interfaccia ListAdapter. È forse questo il metodo             oriented. Originariamente
                                                                                                                                       impiegato dal linguaggio
    this.twitter = twitter;                                            più interessante, poiché è colui il quale si occupa di
                                                                                                                                       Smalltalk, il pattern è stato
    adapter = new ArrayAdapter<String>(context, viewId);               riempire l'oggetto adapter con i tweet che recupe-              esplicitamente o
    refresh();                                                         riamo tramite la libreria Twitter4j (più precisamen-            implicitamente integrato da
}                                                                      te per mezzo dell'oggetto twitter passato al costrut-           numerose tecnologie
                                                                       tore). Si è infatti scelto di preferire l'incapsulamen-         moderne, come framework
                                                                                                                                       basati su PHP, su Ruby
public boolean hasStableIds() {                                        to all'ereditarietà. Per essere più chiari abbiamo
                                                                                                                                       (Ruby on Rails), su Python
    return adapter.hasStableIds();                                     fatto questo: dovevamo implementare un'interfac-                (Django), su Java (Swing,
}                                                                      cia (ListAdapter) ed esiste una classe (Array                   JSF e Struts), su Objective C
public boolean areAllItemsEnabled() {                                  Adapter) che, oltre a fornire una implementazione               e su .NET.
    return adapter.areAllItemsEnabled();                               per tale interfaccia, ha un comportamento molto
}                                                                      simile a quello che vogliamo ottenere. Abbiamo
public int getCount() {                                                così dichiarato un membro privato (ossia abbiamo
    return adapter.getCount();                                         incapsulato) di tale classe e abbiamo definito una
}                                                                      serie di metodi delegate che rigirano la chiamata
public String getItem(int position) {                                  sulla classe incapsulata, che perciò svolge effettiva-
  return adapter.getItem(position);                                    mente il lavoro per conto della classe contenitrice.
}                                                                      In questo modo, l'unico metodo suppletivo che
public long getItemId(int position) {                                  abbiamo avuto veramente la necessità di imple-
  return adapter.getItemId(position);                                  mentare, è stato, come già accennato, il metodo
}                                                                      refresh.
public int getItemViewType(int position) {
  return adapter.getItemViewType(position);
}
public View getView(int position, View                                 CATTURARE GLI EVENTI
                                    convertView, ViewGroup parent) {   DEL DISPLAY
  return adapter.getView(position, convertView, parent);               Rifacendoci al pattern MVC, possiamo affermare
}                                                                      che fin qui abbiamo discusso e analizzato le parti
public int getViewTypeCount() {                                        View (ossia i componenti grafici) e Model (vale a
  return adapter.getViewTypeCount();                                   dire TwitterAdapter); non ci rimane, quindi, che
}                                                                      occuparci del Controller.
public boolean isEmpty() {                                             In precedenza è già stato anticipato che avremmo


h t t p : / / w w w. i o p r o g r a m m o . i t
     96                                                                                                                            And roi / 65 G
                                                                                                                         Novembre 2009 d pr o g r am m in g
                                         La classe Activity e              dell’interfaccia con
   La classe Activity e il disegno dell’interfaccia con Android il disegnoAndroid programming Android
                    MOBILE �


                                    avuto la necessità di recuperare dei componenti         sorgenti. Essendo Twitter4j una libreria open sour-
                                    definiti nell'XML. Uno dei motivi è quello di riusci-   ce, possiamo tranquillamente prelevare i sorgenti
                                    re a intercettare l'evento di pressione del bottone     ed inserirli come package nel nostro progetto.
                                    send; per ottenere ciò si è proceduto come segue:       Sfortunatamente ciò non è ancora sufficiente.
                                                                                            Infatti, in alcune limitate porzioni del codice, tale
                                    btn =(Button)findViewById(R.id.button);                 libreria fa uso delle librerie DOM per l'XML.
                                    btn.setOnClickListener(this);                           Per ovvie ragioni di occupazione in memoria di un
                                    …..                                                     oggetto DOM, Android, essendo progettato per
                                    @Override                                               architetture embedded, non fornisce una completa
                                    public void onClick(View v)                             interfaccia di questo tipo per il parsing di un XML
                                    {                                                       bensì solo una di tipo SAX. D'altro canto i punti
                                        try                                                 dove viene utilizzata sono ben localizzati e non
                                        {                                                   sono così vitali per il funzionamento complessivo
                                            String txt = text.getText().toString();         della libreria stessa.
                                            twitter.updateStatus(txt);                      Per ragioni di spazio non riporteremo le piccole
                                            adapter.refresh();                              modifiche apportate alla libreria, ad ogni modo, il
                                    } catch (TwitterException e)                            codice nel CD allegato contiene già la libreria
                                    {                                                       modificata per essere compilata per Android.
                                    text.setText(e.getMessage());                           Ci rimane un'ultima cosa da fare affinché la nostra
                                    }                                                       applicazione sia completamente funzionante su
                                    }                                                       Android: concedere i permessi di connessione a
                                                                                            Internet.
                                    Niente di più semplice: la nostra Actvity implemen-     Per fare ciò aprite il file AndroidManifest.xml e clic-
                                    ta anche l'interfaccia OnClickListener e ne imple-      cate su Add e selezionate Uses Permession; dalla
                                    menta perciò il metodo onClick. La logica in esso       combo box selezionate poi android.permission.
                                    contenuta è estremamente lineare:                       INTERNET. Dovreste così ritrovarvi in una soluzio-
                                                                                            ne analoga a quella riportata in Fig. 3.
                                    1. si recupera il testo da inviare dalla TextView;
                                    2. si spedisce tale testo al web service tramite la
                                       libreria Twitter4j;
                                    3. infine si aggiorna l'adapter poiché è sicuramente
                                       entrato un altro tweet nella nostra time-line.
            L’AUTORE
                                    Impostata l'Activity come listener del bottone, ogni
       Laureato in ingegneria       volta che quest'ultimo verrà premuto, sarà invoca-
             elettronica presso
                                    to il metodo appena descritto.
       l'università Politecnica
delle Marche, lavora presso
   il reparto R&D della Korg
          S.p.A. Nei limiti della
         disponibilità di tempo     IMPORTARE LA LIBRERIA
          risponde all'indirizzo
andrea.galeazzi@gmail.com
                                    TWITTER4J SU ANDROID
                                    Fin qui abbiamo sempre dato per scontato che nel        Fig. 3: Editor di Android Manifest in cui sono stati
                                    nostro progetto fosse presente la libreria Twitter4j    aggiunti i permessi di accesso a Internet
                                    che abbiamo utilizzato basandoci sull'esperienza
                                    fatta nell'articolo precedente. È anche vero che,
                                    sempre nello scorso articolo, avevamo accennato
                                    al fatto che Android non implementa una Java VM         CONCLUSIONI
                                    classica, bensì la Dalvik virtual machine. Molto sin-   Abbiamo così ultimato un client Twitter per
                                    teticamente diciamo che essa è ottimizzata per          Android, che ci ha permesso di acquisire un discre-
                                    sfruttare la poca memoria presente nei dispositivi      to know-how sia riguardo il sistema operativo di
                                    mobili, consente di far girare diverse istanze della    Google, sia riguardo la nuova piattaforma di social
                                    macchina virtuale contemporaneamente e                  network che sta vedendo tassi di crescita enormi.
                                    nasconde al sistema operativo sottostante la            Naturalmente il client qui sviluppato implementa
                                    gestione della memoria e dei thread. Ciò che inte-      solamente le funzionalità base di Twitter. Avete
                                    ressa noi come sviluppatori è il fatto che il byteco-   ormai però tutte le conoscenze necessarie per
                                    de con cui lavora non è Java. Ne consegue che non       estenderle.
                                    è possibile referenziare direttamente i jar tipica-
                                    mente distribuiti, ma è necessario ricompilare i                                                      Andrea Galeazzi

                                                                                                                        h t t p : / / w w w. i o p r o g r a m m o . i t
   G 66 / Novembre 2009
A n d ro id p r o g r a m m ing                                                                                                                             97
                            MOBILE �
                       Android programming Il framework Funambol per sincronizzare i dati personali
                                                  Il framework Funambol per sincronizzare i dati personali




ANDROID DIALOGA
CON OUTLOOK
IL PARADIGMA DEL “DATA ON THE CLOUD” RISULTA COMODO QUANDO SI VOGLIONO GESTIRE
LE STESSE INFORMAZIONI DA DIVERSI CLIENT, ETEROGENEI TRA LORO. IN QUESTO ARTICOLO
LO ADOPEREREMO PER TENERE SINCRONIZZATE DELLE NOTE TRA ANDROID E OUTLOOK




                                      I
                                          cellulari di ultima generazione hanno portato        3. Un client per Android e uno per Outlook che per-
                                          la gestione dei dati in mobilità a livelli mai          mettano di gestire e sincronizzare in locale que-
                                          sperimentati fino ad oggi: si possono consul-           ste informazioni, nel nostro caso le note di
                                      tare mappe satellitari che mostrano la nostra               Outlook.
                                      posizione, visionare documenti e condividerli
                                      con i collaboratori, raccontare in tempo reale ciò       È chiaro che realizzare tutto da zero risulterebbe
                                      che ci accade con foto e video. In tutti questi sce-     oltremodo oneroso, ma per fortuna tante tessere di
                                      nari le informazioni sono memorizzate in un ser-         questo mosaico esistono già. Partiamo dal proto-
 ❑ CD ❑ WEB                           ver, con i client che possono leggerle, modificar-       collo: invece di inventarcene uno, con un grande
 FunambolSyncNotepad.zip              le, crearne di nuove. In casi particolari i client       dispendio di tempo, possiamo usare qualcosa di
               cdrom.ioprogrammo.it   memorizzano in locale una copia di quanto pre-           già esistente, con il vantaggio di avere alle spalle
                                      sente sul server e, grazie ad apposite procedure         anni di utilizzo e librerie già pronte: stiamo parlan-
                                      di sincronia, questa viene tenuta coerente con i         do di SyncML. Questo protocollo nasce proprio allo
                                      dati originali. Lo scopo di questo articolo è quel-      scopo di gestire le operazioni di sincronizzazione
                                      lo di realizzare un sistema in grado di gestire e        dei dati tra server e smart device, conservando la
                                      sincronizzare delle note tra Outlook e un disposi-       massima libertà sul tipo di dato scambiato. Nelle
                                      tivo Android. Costruiremo prima di tutto un ser-         sue specifiche, vengono definiti i tipi di sincronia
                                      ver dove memorizzare le nostre note, configure-          possibili, i flussi di ognuna di queste, codici di erro-
                                      remo Outlook per accedervi ed estenderemo                re, formato dei messaggi che si possono scambiare
                                      un'applicazione Android già esistente, aggiun-           in ogni fase, casistiche ed esempi di utilizzo.
                                      gendo la capacità di sincronizzare le note che           Anche per quanto riguarda la parte server possia-
                                      questa già gestisce con il nostro server. Una volta      mo risparmiare tempo sfruttando qualcosa di già
                                      capito il meccanismo di base, si potranno aggan-         esistente, come il software realizzato da Funambol.
                                      ciare ulteriori applicazioni, come Thunderbird,          Funambol Community Edition è la versione open
                                      un programma desktop o un sito web.                      source di una piattaforma per la sincronia “on the
                                                                                               cloud” di dati personali come contatti, calendario,
                                                                                               note. Con un'approssimazione riduttiva possiamo
                                                                                               dire che realizza i primi due punti dell'elenco pre-
           REQUISITI
                                      ARCHITETTURA                                             cedente e utilizza, per lo scambio dei dati con i
 Conoscenze richieste
                                      DELL'APPLICAZIONE                                        client, proprio il protocollo SyncML. Laddove non
    Java                              Partendo da una panoramica di massima, un'infra-         supportato nativamente, vengono messi a disposi-
                                      struttura in grado di gestire la sincronizzazione dei    zione dei plug-in per effettuare la sincronia: ne esi-
                                      dati tra diversi client deve essere composta, alme-      stono per la maggior parte dei sistemi operativi
                                      no, dai seguenti elementi:                               mobile, da Symbian ad iPhone, troviamo plugin
 Software
     Java SDK (JDK) 5+,                                                                        per Outlook e Thunderbird, sono stati realizzati
     Eclipse 3.3+
                                      1. Un server “on the cloud” dove memorizzare i           connettori per eGroupware del calibro di Exchange
                                         dati.                                                 e Zimbra. Esistono SDK per Java, J2ME e C++, per
                                      2. Un motore di sincronia che sappia tenerli alli-       aggiungere capacità di sincronia con un server
 Impegno                                 neati tra diversi client, capace di eseguire opera-   Funambol all'interno di tutte le applicazioni che
                                         zioni di creazione, aggiornamento, cancellazio-       ancora non la supportano. Rimane scoperta solo la
                                         ne, risoluzione dei duplicati e notifica dei cam-     parte riguardante il client per Android. Su questo
Tempo di realizzazione
                                         biamentiun protocollo con cui scambiare i dati        aspetto, terminata la creazione dell'infrastruttura,
                                         tra i client e il motore.                             andremo a focalizzare la nostra attenzione.

                                                                                                                          h t t p : / / w w w. i o p r o g r a m m o . i t
  G 44 / Marzo 2010
  98                                                                                                                                   And roi d pr o g r am m in g
           Il framework Funambol per sincronizzare i dati personali
     Il framework Funambol per sincronizzare i dati personali                                     � MOBILE
                                                                                               Android programming


                                                          dard SyncML, Funambol gestisce sette tipi di sin-
                                                          cronia, di cui uno è un alert che indica al client che
                                                          è necessario sincronizzarsi con il server, mentre gli
                                                          altri guidano il flusso dei dati:

                                                          • REFRESH_FROM_SERVER: invia al client tutti gli
                                                            elementi presenti sul server, sovrascrivendo
                                                            completamente quanto presente sul client.
                                                          • REFRESH_FROM_CLIENT: invia al server tutti gli
                                                            elementi presenti sul client, sovrascrivendo com-
                                                            pletamente quanto presente su server.
Fig. 1: Una volta sincronizzati i dati con il server                                                                          NOTA
                                                          • ONE_WAY_FROM_SERVER: il server manda al
Funambol, è possibile accedervi anche dal web, tramite      client solo gli elementi nuovi, modificati o can-
my.funambol.com
                                                            cellati dall'ultima sincronia.
                                                                                                                    SYNCML
                                                                                                                    Il protocollo SyncML, ad
                                                          • ONE_WAY_FROM_CLIENT: il client manda al                 oggi conosciuto anche
                                                            server solo gli elementi nuovi, modificati o can-       come Open Mobile
                                                            cellati dall'ultima sincronia.                          Alliance Data
CREAZIONE                                                 • TWO_WAY_SYNC: il tipo di sincronia più usato,           Synchronization and
                                                                                                                    Device Management, è
DELL'INFRASTRUTTURA                                         dove client e server si scambiato gli elementi
                                                                                                                    nato negli anni 90 con
Prima di tutto, occorre configurare l'ambiente di           nuovi, modificati o cancellati dall'ultima sincro-      l'obiettivo di garantire uno
test. Come dicevamo, la logica per lo storaging             nia. Il primo a farlo è il client, poi il server.       standard aperto e
delle informazioni, per il motore di sincronia e per      • SLOW_SYNC: il client manda tutti i suoi dati al         platform-independent per
il trasporto dei dati attraverso il protocollo SyncML       server, questo li confronta con quanto possiede,        la sincronizzazione dei dati
                                                                                                                    tra i primi cellulari e i
1.2.1 sono implementate dal server Funambol:                determinando quali elementi aggiungere, modi-
                                                                                                                    computer desktop. Usato
abbiamo la possibilità di utilizzarne sia una versio-       ficare e cancellare per allineare le due basi dati.     prevalentemente nella
ne online (http://my.funambol.com), sia di eseguire in      Al termine dell'analisi, il server invia le modifiche   sincronia dei contatti e del
locale la Community Edition, Basta scaricare il pac-        che anche il client deve effettuare per completa-       calendario, in realtà
chetto per Windows o per GNU/Linux disponibile              re l'allineamento.                                      SyncML si occupa solo
                                                                                                                    della parte di trasporto, a
all'indirizzo http://www.forge.funambol.org/down-
                                                                                                                    prescindere dal contenuto
load, eseguirlo e lanciare il server tramite lo script    Unità di base per il trasporto dei dati è il SyncItem,    di quanto trasportato. Per
da riga di comando:                                       un oggetto che contiene il dato da sincronizzare e        questo trova applicazioni
                                                          alcune informazioni a corredo. Cuore del processo         anche in altri ambiti, come
 bin/funambol.cmd start                                   di sincronia è la SyncSource, una classe che fa da        quello del backup. Per
                                                                                                                    maggiori informazioni
                                                          ponte tra il server ed il client ed ha il compito di
                                                                                                                    http://www.openmobilea
Per il client Outlook, si può installare la versione XP   esporre i metodi per aggiungere, cancellare e modi-       lliance.org/tech/affiliates/
o 2003 fornita con Office, oppure utilizzare la ver-      ficare i dati su quest'ultimo e per sapere quali sono     syncml/syncmlindex.html
sione trial disponibile sul sito Microsoft. Occorre       i nuovi elementi, quelli modificati e quelli cancella-
poi installare e configurare il Funambol Sync Client      ti dall'ultima sincronia, sempre sul client. Ultimo
for Microsoft Outlook, un'estensione di Outlook           elemento del processo, il SyncManager, che viene
che permette di sincronizzare Contatti, Calendario        chiamato per effettuare la sincronia passandogli la
e Note con il server Funambol. Anch'esso si può           SyncSource da usare. Nel client per Outlook, ad
scaricare gratuitamente dalla Funambol Forge, con         esempio, sono state create delle SyncSource per i
la documentazione necessaria alla sua messa in            contatti, per gli appuntamenti e per le note, mentre
opera. In ultimo, necessitiamo dei tool per creare        in questo articolo ne creeremo una apposita per le
applicazioni Android: nell'articolo faremo uso di         note, chiamata NoteSyncSource.
Eclipse e dell'Android SDK, configurato secondo la        Per capire come interagiscono questi elementi,
guida ufficiale di Google, reperibile su http://devel-    occorre analizzare da vicino il flusso e i ruoli tipici
oper.android.com/sdk.                                     di un'operazione di sincronia:

                                                          • Viene creata una nuova SyncManager, passando-
                                                            gli una SyncManagerConfig dalla quale ottenere
L'ARCHITETTURA                                              le configurazioni per il processo di sincronia
DI FUNAMBOL                                                 (username, password, indirizzo del server ecc).
La parte focale del nostro client non dovrà fare altro
che richiedere al server Funanbol una sincronia           • Viene creata una nuova NotesSyncSource, pas-
delle note e aggiornare di conseguenza i propri             sandogli una NotesSyncSourceConfig dalla quale
dati, comunicando anche eventuali variazioni fatte          ottenere le configurazioni per la specifica opera-
in locale. Rispettando quanto dettato dallo stan-           zione di sincronia (tipo di dati gestiti, dati remo-

h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                Marzo 2010 / 45 99
                                                                                                                               G
                          MOBILE �
                     Android programming Il framework Funambol per sincronizzare i dati personali
                                                Il framework Funambol per sincronizzare i dati personali


                                    ti con cui sincronizzarsi, timestamp dell'ultima         abbiamo inserito nel menu principale una nuova
                                    sicronia effettuata ecc).                                voce in grado di richiamarla e abbiamo modificato
                                                                                             lo strato di accesso ai dati per gestire più agevol-
                                  • Viene chiamanto il metodo SyncManager.sync               mente le informazioni racchiuse nella classe Note.
                                    passandogli NotesSyncSource come SyncSource.

                                  • Il SyncManager contatta il server Funambol, si
                                    autentica e si accorda con esso su quale tipo di
                                    sincronia eseguire per il tipo di dati gestito dalla
                                    SyncSource.

                                  Se non viene specificato diversamente, la prima            Fig. 2: L'Activity principale dell'applicazione Notepad...
                                  tentata è una TWO_WAY_SYNC. A secondo del tipo
                                  di sincronia, il SyncManager trasmette al server
                                  Funambol i dati sugli elementi aggiunti, modificati        Come dicevamo prima, il protocollo SyncML si
                                  e cancellati nel client, ricavati grazie ai metodi della   occupa solo dello strato di trasporto, lasciando
                                  SyncSource e ai paramentri LastAnchor e                    piena libertà sui dati trasportati. Per questo il ser-
                                  NextAnchor, che indicano l'intervallo di tempo             ver Funambol definisce un formato, il SIF-N, per
                                  all'interno del quale considerare le modifiche             inserire oggetti di tipo note dentro ai messaggi
          NOTA                    richieste. Il server Funambol analizza quanto otte-        SyncML, in modo da essere indipendente da come
                                  nuto, aggiorna i suoi dati e trasmette le sue modifi-      ogni client le persiste nel suo storage locale. Per i
             FUNAMBOL             che al SyncManager, che le persiste sul client grazie      contatti e per gli appuntamenti, invece, viene usato
 Nata circa 10 anni fa dalla      ai metodi addItem, deleteItem e removeItem della           lo standard VCard. Occorrerà quindi serializzare in
     visione di un ingegnere      SyncSource.                                                SIF-N le note ed inserirle in dei SyncItem prima di
             italiano, Fabrizio
     Capobianco, Funambol         Al termine della sincronia, vengono aggiornati             mandarle al server, mentre, per ogni SyncItem
    oggi offre un prodotto di     LastAnchor e NextAnchor della SyncSource.                  inviato da quest'ultimo al client, verrà estratto il
       sincronia dati “on the     Funambol mette a disposizione un progetto chia-            contenuto, deserializzato dal SIF-N e convertito in
 cloud” sotto licenza Affero      mato client-sdk, sempre reperibile nella sezione           un oggetto Note. I due helper che si occupano di
       GPL2, comprensivo di       download della Forge, contenente librerie e docu-          queste operazioni sono, rispettivamente,
     client ed estensioni per
     moltissime piattaforme       mentazione per usare i suoi servizi con diverse tec-       NoteToSIFN e SIFNParser, utilizzati nei metodi di
        mobili e non. Data la     nologie: Java, C++ e J2ME. Al momento della scrit-         NoteDao. Non occorre scendere nel dettaglio di
     natura totalmente open       tura di questo articolo, inoltre, è in fase sviluppo
source del prodotto, tutto il     anche l'SDK per Android, presente per ora solo
           codice sorgente è      all'interno del progetto android-client e in grado di
  liberamente disponibile e,
grazie a ciò, nel tempo si è      sincronizzare contatti e appuntamenti (https://
      creata una community        android-client.forge.funambol.org). Per maggiori
 intorno al progetto, che ha      informazioni, rimandiamo al box laterare con un
    sviluppato connettori ed      elenco di link a diversi documenti informativi.
      estensioni per ulteriori
  ambienti, oltre a quelli già
    supportati. Per maggiori
                  informazioni
      www.funambol.org            CLIENT ANDROID:
                                  GESTIONE DATI
                                  Allo scopo di semplificare il processo di sviluppo,
                                  minimizzare il codice da scrivere e concentrarsi
                                  unicamente sulle funzionalità di sincronia, abbia-
                                  mo modificato ed esteso un'applicazione Android
                                  già esistente, il famoso Notepad presente nel tuto-
                                  rial online introduttivo alla piattaforma
                                  (http://developer.android.com/guide/tutorials/notep-
                                  ad). Sono state incluse le librerie del funambol-sdk
                                  per android e, direttamente dal Funambol Java
                                  SDK, sono state aggiunte alcune classi presenti nei
                                  package com.funambol.*, che implementano l'og-
                                  getto Note e i metodi per la sua conversione.
                                  Successivamente, abbiamo creato una nuova atti-
                                  vità per i impostare le configurazioni necessarie ad       Fig. 3: … e quella per la creazione e la modifica
                                  usare il server Funambol e lanciare una sincronia,         di una nota


                                                                                                                           h t t p : / / w w w. i o p r o g r a m m o . i t
  G 46 / Marzo 2010
  100                                                                                                                                   And roi d pr o g r am m in g
           Il framework Funambol per sincronizzare i dati personali
     Il framework Funambol per sincronizzare i dati personali                                                    � MOBILE
                                                                                                              Android programming


queste due classi, dato che sono prese direttamen-                       riquadro che la contiene, categorie di appartenen-
te dal client-sdk e possono funzionare per noi                           za e folder in cui è inserita. Attualmente il nostro
come una black-box. L'appena citato NotesDao è il                        client non fa uso queste informazioni, ma dato che
nostro Data Access Object, una classe che fa da                          sono tutte incluse nel processo di sincronia, future
ponte tra i SyncItem e le informazioni grezze pro-                       implementazioni non avrebbero difficoltà a farlo.
venienti da NotesDbAdapter, occupandosi delle                            Inoltre Outlook permette di modificare solo il
operazioni di conversione, gestione dei timestamp                        corpo della nota, e non il titolo. La query per crea-
e degli status. Il metodo getNoteFromSyncItem                            re la tabella, dentro la classe NotesDbAdapter,
viene usato per convertire il contenuto di un                            diventa quindi la seguente:
SyncItem in un oggetto Note: prima viene istanzia-
to un parser passandogli il contenuto preso dal                          private static final String DATABASE_CREATE =
SyncItem, poi viene invocato il suo metodo parse                               "create table notes (" +
per ottenere la Note. Tra le due chiamate, c'è la                                 "_id integer primary key autoincrement, " +
gestione delle possibili eccezioni generate.                                      ...


 SIFNParser parser = null;                                               Come si può notare, sono stati aggiunti anche due
 InputStream is = new                                                    campi per le informazioni funzionali al processo di                   NOTA
       ByteArrayInputStream(syncItemData.getContent());                  sincronia: status dell'elemento e data di ultimo
 try {                                                                   aggiornamento. Tra i diversi valori che lo status           FUNAMBOL FORGE
       parser = new SIFNParser(is);                                      può assumere, ci sono quelli di NEW, UPDATED e              Funambol Forge è un
 } catch (SAXException e) {                                              DELETED, mentre last_update contiene il time-               repository di progetti in
 ...                                                                     stamp di questo cambio di status. NoteSyncSource            stile SourceForge che
                                                                                                                                     ospita sia i progetti
                                                                         deve infatti sapere quali sono le note nuove, modi-         sviluppati e manutenuti da
La conversione opposta, da Note a SIF-N, avviene                         ficate o cancellate in un range temporale, general-         Funambol, sia quelli creati
nel metodo getSyncItemFromNote, che passa al                             mente dall'ultima sincronia al momento corrente,            e gestiti dalla community.
costruttore del converter fuso orario e codifica con                     e per farlo si appoggia NoteDao, sfruttando questi          La home page contiene
cui l'oggetto Note verrà convertito, inserendo il                        due campi. La seguente query, ad esempio, per-              informazioni generali su
                                                                                                                                     Funambol con accesso
risultato di questa operazione all'interno di un                         mette di trovare le note create successivamente             diretto alle pagine di
SyncItem,     settandone       anche      il    tipo                     all'ultima operazione di sincronia andata a buon            download dei vari
(NOTE_ITEM_TYPE) e la chiave (il progessivo della                        fine:                                                       componenti, server e
nota).                                                                                                                               client, documentazione e
                                                                         StringBuilder where = new StringBuilder();
                                                                                                                                     altro. Il progetto Core e i
                                                                                                                                     sottoprogetti contengono
 NoteToSIFN converter;                                                   where.append(KEY_LASTUPDATED).append(">").appe
                                                                                                                                     la maggior parte del
 String convertedContent;                                                                                              nd(since)     codice di Funambol
 TimeZone tz =                                                              .append(" AND ")                                         Community Edition. Sul
                             Calendar.getInstance().getTimeZone();       .append(KEY_LASTUPDATED).append("<").append(to              Forge sono anche ospitate
 converter = new NoteToSIFN(tz, "UTF-8");                                                                                       );
                                                                                                                                     le pagine per i programmi
                                                                                                                                     di partecipazione alla
 try {                                                                      .append(" AND ")
                                                                                                                                     community Funambol,
       convertedContent =                                                .append(KEY_STATUS).append("='").append(status).a           come i Code Sniper, Phone
                                     converter.convert(noteToConvert);                                                ppend("'");    Sniper e L10n Sniper:
 } catch (ConverterException e) {                                                                                                    occasioni per entrare in
       Log.e("getSyncItemFromNote", e.getMessage());                     Cursor mCursor =
                                                                                                                                     contatto con questo
                                                                                                                                     mondo, con la sicurezza di
       return null;                                                         mDb.query(DATABASE_TABLE,
                                                                                                                                     essere retribuiti per il
 }                                                                                ALL_TABLE_COLUMNS,                                 lavoro fatto.
 Log.i("getSyncItemFromNote", convertedContent);                                  where.toString(),
 SyncItem item = new SyncItem(noteToConvert.                                      null, null, null, null);
                               getUid().getPropertyValueAsString());     return mCursor;
 item.setContent(convertedContent.getBytes());
 item.setType(NOTE_ITEM_TYPE);                                           status contiene il valore SyncItemState.NEW, che
 item.setKey(noteToConvert.getUid().getPropertyValue                     indica una nuova nota, mentre le variabili since e to
                                                          AsString());   contengono due timestamp, rispettivamente quello
 return item;                                                            della data dell'ultima sincronia e quello del momen-
                                                                         to corrente. Sono entrambi memorizzati nel client
Rispetto all'originale del tutorial, nel database                        grazie alla classe NotePreferences come campi
usato per contenere i dati del client sono stati                         LastAnchor e NextAnchor. La seconda viene inviata
aggiunti tutti gli ulteriori campi che Outlook                           dal server all'inizio di ogni operazione di sincronia
memorizza per ogni nota: una data ad essa asso-                          e, se questa va a buon fine, viene memorizzata in
ciata, colore, coordinate X, Y, larghezza e altezza del                  LastAnchor al suo termine. Allo scopo di mettere in

h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                                 Marzo 2010 / 47 G
                                                                                                                                              101
                          MOBILE �
                     Android programming Il framework Funambol per sincronizzare i dati personali
                                                Il framework Funambol per sincronizzare i dati personali


                                  grado la SyncSource di conoscere le note rimosse sul      nota arrivata dal server chiamerà il metodo
                                  client dall'ultima sincronia, abbiamo scelto di elimi-    NoteSyncSource.addItem
                                  narle in modalità soft-deletion, cioè senza cancellare
                                  fisicamente il record corrispondente alla nota, ma        @Override
                                  impostando a 'D' il suo status e aggiornando il time-     public int addItem(SyncItem item)
                                  stamp presente in last_update. Coerentemente con             throws SyncException
                                  questa politica di soft-deletion, modifichiamo il         { ... }
                                  metodo NoteDbAdapter.fetchAllNotes, introducendo
                                  il seguente controllo sullo status di un record del DB:   A sua volta, superato il controllo della possibilità di
                                                                                            aggiungere un elemento per il tipo di sincronia cor-
                                  public Cursor fetchAllNotes()                             rente, NoteSyncSource.addItem chiama il medoto
                                  {                                                         NoteDao.addNote
                                      return mDb.query(DATABASE_TABLE,
                                                    new String[] {KEY_ROWID, KEY_TITLE,     public int addNote(SyncItem item, int key) {... }
                                                                              KEY_BODY},

          NOTA                          KEY_STATUS + "<>'D'",                               Come si legge dal codice, il valore di ritorno del
                                        null, null, null, null);                            metodo NoteSyncItem.addItem viene impostato su
       MYFUNAMBOL                 }                                                         200 quando un'operazione va a buon fine, secondo
                MyFunambol                                                                  quanto dettato dallo standard SyncML. Valori come
(http://my.funambol.com)          Ricordiamoci comunque che, forzando nel                   500, ad esempio, indicano invece diversi tipi di erro-
    è il portale, liberamente     NoteSyncSourceConfig una sincronia di tipo                ri. Rispetto al programma Notepad originale, è stata
 utilizzabile, per provare le     REFRESH_FROM_SERVER, tutte le note presenti               aggiunta nella nostra applicazione una nuova
   funzionalità offerte dalla
     piattaforma Funambol.        sul client vengono fisicamente cancellate. Questo         Activity, FunambolSettings, che permette di specifi-
 Una volta registrati, si può     tipo di sincronia va usato per riportare sul client       care username, password e server sul quale effettua-
scaricare il client adatto al     quanto contenuto sul server, senza che il primo           re la sincronia, oltre che ad esporre una TextView
          tipo di smartphone      possa trasmettere le ultime modifiche a quest'ulti-       contenente i messaggi. Il log delle singole operazio-
    posseduto e lanciare la       mo. Si può anche impropriamente usare una                 ni della sincronia è reso possibile da NoteListerner,
 prima sincronia. Oltre alla
       possibilità di gestire i   REFRESH_FROM_SERVER per fare un po' di pulizia            una classe derivante da SyncListener che viene
              contatti, note e    e liberare risorse sul client, sempre preziose, se si     agganciata a NoteSyncSource in fase di creazione di
  appuntamenti via web, il        creano e cancellano note in modo intensivo.               quest'ultima. Il meccanismo di funzionamento è
  portale può essere usato                                                                  semplice, dato che la SyncSource chiama i diversi
come semplice backup dei
dati del propro dispositivo,
funzionalità utile in caso di
  perdita o sostituzione del      CLIENT ANDROID:
device. Se si è sempre alla       LA SINCRONIA DATI
       ricerca di funzionalità    Passiamo ora alla creazione dell'elemento più
     borderline, all'indirizzo    importante della sincronia: la classe NoteSync-
http://dogfood.funambol
   .com è raggiungibile la        Source. In fase di inizializzazione, le viene passata
    versione di beta-testing      un'ulteriore classe, NoteSyncSourceConfig, che con-
   dello stesso portale, con      tiene le configurazioni minime di cui la SyncSource
            implementate le       necessita:
ultimissime funzionalità da
sperimentare. Attualmente,
                                  public NoteSyncSourceConfig(Activity a) {...}
    ad esempio, è possibile
        assegnare ai propri
     contatti la foto del loro    Sono fondamentali la RemoteUri, che indica il data-
       profilo su Facebook.       base su server Funambol da utilizzare per sincroniz-
                                  zare i dati, quello delle note appunto, e il Type dei
                                  dati contenuti all'interno del SyncItem gestito dalla
                                  SyncSource. Nel nostro caso, come avevamo spiega-
                                  to, viene usato il SIFN, mentre per i contatti avrem-
                                  mo trovato un Type uguale a text/x-vcard. Non viene
                                  applicato nessun tipo di Encoding al contenuto del
                                  SyncItem. Troviamo anche l'Activity che serve per
                                  ottenere l'Application Context necessario alla
                                  SyncSource per molte delle sue operazioni. Gli altri
                                  medoti di NoteSyncSource sono abbastanza sempli-          Fig. 4: L'Activity che abiamo aggiunto ci consente di
                                  ci e quasi sempre corrispondenti ad un metodo su          impostare username, password e server da usare
                                                                                            per sincronizzare le nostre note...
                                  NoteDao. Ad esempio, l'inserimento di una nuova

                                                                                                                        h t t p : / / w w w. i o p r o g r a m m o . i t
  G 48 / Marzo 2010
  102                                                                                                                                And roi d pr o g r am m in g
          Il framework Funambol per sincronizzare i dati personali
    Il framework Funambol per sincronizzare i dati personali                                         � MOBILE
                                                                                                  Android programming


metodi del listener in base alla tipologia di operazio-   valori (l’oggetto SharedPreferences) per poi chiamare
ne svolta. Questi metodi, implementati nel nostro         i metodi del Context che permettono di caricarlo e di
NoteListerner, non fanno altro che aggiornare la          persisterlo per mezzo dell'oggetto SharedPre-
TextView con i log, accodando il nuovo messaggio.         ferences.Editor. Ogni Context può contenere molte-
                                                          plici oggetti SharedPreferences, ognuno di essi iden-
                                                          tificato da un nome univoco. Nella nostra applica-
                                                          zione, abbiamo usato l'identificativo fnblPref. Di
                                                          seguito un classico esempio di creazione di un con-
                                                          tainer per le preferenze: memorizzazione di un valo-
                                                          re di tipo stringa facente capo alla chiave “syncUrl” e
                                                          lettura di quest'ultimo.

                                                          public static void getAndSetPreference(Activity a) { ... }


                                                          L'Activity corrente viene usata per ricavare il riferi-
                                                          mento al Context dell'applicazione. È chiaro che
                                                          questo metodo è utile per piccoli e semplici insiemi
                                                          di dati, mentre per qualcosa di più articolato e com-
                                                          plesso occorrerà rivolgersi al altre tecniche di stora-
                                                          ge persistente dei dati. Nell'Activity che si occupa
                                                                                                                                     NOTA
                                                          della sincronia, in base al bottone premuto, viene
                                                          richiesto un diverso tipo di sincronia: una
                                                          SyncML.ALERT _CODE_REFRESH_FROM_SERVER
                                                                                                                          L'INDIRIZZO
                                                                                                                          DEL SERVER
                                                          che forza una cancellazione dei dati del client e               Se si sta usando la
                                                          prende in carico solo quelli presenti sul server,               versione online di
                                                          oppure una SyncML.ALERT_CODE_FAST, che tenta                    Funambol, l'URI del server
                                                          invece di eseguire la classica TWO_WAY_SYNC, ope-               con cui sincronizzare i dati
                                                          razione in cui client e server si scambiano solo le             sarà
                                                                                                                          http://my.funambol.com/s
Fig. 5: … ed ecco il log della nostra prima sincronia!    modifiche dall'ultima sincronia terminata con suc-              ync, mentre se si sta
                                                          cesso. Seguendo le linee guida per lo sviluppo di               usando quella in locale,
                                                          applicativi, questo blocco viene gestito come thread            l'URI sarà
                                                          separato rispetto all'applicazione principale, in               http://indirizzo_ip_locale:
                                                                                                                          8080/funambol/ds, dove
                                                          modo da non bloccarla e da poter mostrare un pro-
                                                                                                                          indirizzo_ip_locale sarà
                                                          gessivo dei log di quanto viene eseguito. Per rag-              l'indirizzo del pc,
                                                          giungere lo scopo, è stata creata la classe privata             raggiungibile dal telefono
                                                          SyncThread, che estende la classe Thread e che                  Android.
                                                          all'interno del metodo Run ha il codice che lancia la
                                                          sicronia vera e propria. Nel seguente frammento di
                                                          codice possiamo vedere l'inizializzazione della
                                                          NotesSyncSourceConfig, alla quale viene passata
                                                          l'Activity corrente e il tipo di sincronia richiesta, l'i-
                                                          nizializzazione della NotesSyncSource, alla quale
                                                          viene passato l'oggetto con le configurazioni della
Fig. 6: Le note sono state trasferite su Outlook          sincronia appena istanziato e l'Activity corrente, l'i-
con successo                                              nizializzazione del NotesListener, al quale viene pas-
                                                          sato l'EditText che conterrà i log e, infine, il collega-
                                                          mento del Listener alla SyncSource:

CLIENT ANDROID:                                           NoteSyncSourceConfig noteconf = new
GLI ALTRI COMPONENTI                                             NoteSyncSourceConfig(FunambolPreferences.this,
Appoggiandosi alla classe BaseSettings, alcune infor-                                                    syncMode);
mazioni inerenti la SyncSource e il SyncManager
vengono memorizzate ricorrendo al meccanismo              NoteSyncSource src = new NoteSyncSource(noteconf,
delle Preferences. Si tratta di una pratica alternativa                                 FunambolPreferences.this);
alla creazione di file o tabelle per conservare infor-    src.setListener(new NoteListener(Funambol
mazioni proprie dell'applicazione, che devono esse-                      Preferences.this, mHandler, txtLogArea));
re mantenute tra un lancio e l'altro. Funziona così: si
memorizzano i dati interessati in una lista di chiavi-                                              Alfredo Morresi

h t t p : / / w w w. i o p r o g r a m m o . i t
A n d ro id p r o g r a m m ing                                                                                        Marzo 2010 / 49 G
                                                                                                                                     103
Questo approfondimento tematico è pensato per chi vuol imparare a programmare e creare
software per gli smartphone con sistema operativo Google Android. La prima parte del testo
guida il lettore alla conoscenza degli strumenti necessari per sviluppare sulla piattaforma
mobile di Mountain View (installazione SDK, librerie e tool di supporto allo sviluppo).
Le sezioni successive sono pensate per un apprendimento pratico basato su esempi di
progetto: dialogo e interazione con l’ambiente operativo del telefonino, interazione con gli
utenti, componenti di un widget, interfacce in XML, gestione del touch, progettazione dei
menu e via dicendo.
Una serie di esempi pratici da seguire passo passo che spingono il lettore a sperimentare sul
campo il proprio livello di apprendimento e lo invitano a imparare divertendosi.




                               www.punto-informatico.it

				
DOCUMENT INFO
Shared By:
Tags: Android
Stats:
views:31
posted:3/13/2013
language:Italian
pages:104