Android Manuale
-
Upload
derek-gutierrez -
Category
Documents
-
view
81 -
download
1
description
Transcript of Android Manuale
La visualizzazione: ViewAndroid fornisce una collezione di controlli studiati e progettati appositamente per i device mobili: il cuore di
questi controlli è rappresentato principalmente da due
classi,android.view.View e android.view.ViewGroup.
Una View è sostanzialmente un’area rettangolare nello schermo responsabile del disegno degli
elementi grafici e della cattura e gestione degli eventi generati dall’utente. Un oggettoViewGroup è
anch’esso una View, ma che contiene altre View.
Nella piattaforma Android si utilizza il concetto di “layout” per gestire l’impaginazione dei controlli
all’interno di un contenitore di oggetti View. Utilizzare i layout facilita la progettazione delle interfacce
perché è più semplice orientare e posizionare i controlli che le compongono.
Possiamo considerare una View come un widget: bottoni, etichette, caselle di testo, tabelle, sono tutti esempi
di controlli e widget che possiamo utilizzare per comporre le interfacce grafiche delle nostre applicazioni.
Come vedremo più in dettaglio nel tutorial passo per passo che concluderà questa guidapossiamo
scegliere approcci diversi per la costruzione delle interfacce in ambiente Android: la prima possibilità è quella
di definire l’interfaccia interamente da codice, altrimenti possiamo scegliere di costruire le interfacce
attraverso delle configurazione XML, oppure ancora possiamo scegliere un approccio “ibrido”, definire le
interfacce in XML e poi, attraverso un riferimento, modificarle e gestirle da codice.
Le attività: ActivityLa classe Activity è uno degli elementi centrali di ogni applicazione Android. L’Activity è un concetto
legato allo sviluppo delle interfacce grafiche: normalmente una Activityrappresenta una singola schermata
della nostra applicazione. Le applicazioni possono definire una o più Activity per trattare diverse fasi del
software: ogni Activity è responsabile del salvataggio del proprio stato in modo da poterlo ristabilire
successivamente come parte del ciclo di vita dell’applicazione.
Generalmente una Activity corrisponde ad un'azione specifica che l’utente può fare: essendo una delle
componenti principali nel ciclo di vita di ogni applicazione Android, il modo in cui le Activity sono lanciate e in
cui interagiscono tra loro è una parte fondamentale nello sviluppo con la piattaforma Android.
Ci può essere solo una Activity attiva per volta, quindi una sola Activity per volta può essere in “primo piano”
(foreground) nello stesso tempo: una Activity che in un determinato momento non si trova nello stato attivo e
quindi non si trova in foreground (in questo caso si dice che l’Activity si trova in backgroud) potrebbe
essere terminata dal sistema operativo ad esempio perché la memoria diventa insufficiente. Questo
significa che ogni applicazione Android può cambiare lo stato in ogni momento e deve essere pronta ad
essere interrotta e chiusa in ogni istante.
Come vedremo la classe Activity dispone di un numero notevole di callback che permettono ad una Activity di
rispondere agli eventi come la sospensione e la ripresa.
Le azioni: IntentUn Intent è un meccanismo che descrive un’azione specifica, come ad esempio “chiamare a casa” o
“inviare un sms”: in Android praticamente ogni cosa passa attraverso un Intent, e lo sviluppatore li può
utilizzare per riusare o sostituire diversi componenti software.
Ad esempio è disponibile un Intent “inviare una email”: se nella nostra applicazione abbiamo la necessità di
gestire l’invio di email possiamo invocare l’Intent che il sistema ci mette a disposizione, oppure possiamo
scriverne uno nuovo e utilizzare quest’ultimo nelle nostreActivity sostituendo l’Intent di default con quello
implementato da noi.
Possiamo immaginare un Intent come un’azione che possiamo far invocare ad Android: un Intent può
essere molto specifico ed essere richiamabile da una specifica Activity oppure può essere generico e
disponibile per qualsiasi Activity che rispetta determinati criteri.
Schematizzando, un Intent può essere utilizzato per:
•trasmettere l’informazione per cui un particolare evento (o azione) si è verificato;
•esplicitare un’intenzione che una Activity o un Service possono sfruttare per eseguire un determinato compito o azione, solitamente con o su un particolare insieme di dati;
•lanciare una particolare Activity o Service;
•supportare l’interazione tra qualsiasi applicazione installata sul dispositivo Android, senza doversi preoccupare di che tipo di applicazione sia o di quale componente software gli Intentfacciano parte.
L’Intent è uno dei concetti e dei meccanismi fondamentali di Android: la sua implementazione trasforma
ogni dispositivo Android in una collezione di componenti indipendenti ma facenti parte di un singolo sistema
interconnesso.
La condivisione dei dati con i Content ProviderUn Content Provider è un contenitore di dati e rappresenta uno dei modi migliori per condividere
informazioni “globali” tra applicazioni. Nel modello di sicurezza implementato in Android, i file scritti da una
applicazione non possono essere letti o scritti da un’altra. Android è un sistema Linux-based in cui ogni
applicativo ha il suo userid Linux, la sua directory “data” (/data/data/nome_pacchetto) e il suo spazio di
memoria dedicato e protetto. Questo è il motivo per cui gli applicativi Android necessitano dei Content
Provider per comunicare tra loro.
I processi possono segnalare se stessi al sistema come Content Provider di un insieme particolare di dati:
quando queste informazioni sono richieste vengono richiamate da Android grazie ad un insieme specifico di
API che permettono di agire sul contenuto secondo le specifiche definite. Alcuni Content Provider, ad
esempio, forniscono l’accesso ai proprio dati solo in lettura, mentre altri permettono alle applicazioni di creare,
aggiornare, modificare o cancellare record, come nel caso di quella che gestisce i contatti.
Un database SQLite in un device Android è un esempio di sorgente di dati che possiamo incapsulare
all’interno di un Content Provider: Chiaramente Android è provvisto di un insieme di Content Provider nativi,
documentati nel package “android.provider” dell’SDK. Possiamo vedere la lista di questi Content Provider sul
sito degli svilupppatori Android.
Per accedere alle risorse fornite da un Content Provider utilizziamo un insieme di URL caratterizzati dallo
schema “content://” con un modello che ricorda molto da vicino le chiamate REST.
Diversi database nativi, come ad esempio quello dei contatti, sono disponibili come Content
Provider rendendosi accessibili anche ad applicativi di terze parti.
Lavoriamo in backgroud con i ServiceUn Service è un processo che gira in background senza la diretta interazione con l’utente (un concetto
molto simile al deamon in ambiente Unix). La classe Service viene utilizzata per creare componenti software
che possono svolgere attività in modo “invisibile”, senza interfaccia utente.
Un esempio tipico di Service lo vediamo implementato nel player di musica, che continua a riprodurre
canzoni anche quando non è in primo piano (foreground) e stiamo utilizzando altri programmi. Il codice
responsabile di questa attività sarà implementato in un Service, al quale successivamente
un’altra Activity potrà “ordinare” di cambiare traccia o di fermare la musica.
Utilizzando i Service possiamo far girare le nostre applicazioni e farle reagire ad eventianche quando non
sono in primo piano: un Service può essere avviato, fermato e controllato da altri componenti
dell’applicazione, inclusi altri Service e Activity. Se la nostra applicazione deve svolgere attività che non
dipendono direttamente dall’input inserito dall’utente, allora implementare un Service potrebbe essere la
risposta alle nostre necessità: applicazioni che si aggiornano regolarmente ma che raramente o ad
intermittenza interagiscono con l’utente sono buone candidate ad essere implementate come Service.
Un Service avviato ha una priorità più alta rispetto ad Activity in stato di inattività, in questo modo vi è
minore probabilità per un Service di essere terminato dal gestore delle risorse di runtime. L’unica ragione per
cui Android potrebbe fermare un Serviceprematuramente è per fornire risorse addizionali al componente
software in primo piano (normalmente una Activity).
Quando questo si verifica il Service fermato sarà riavviato automaticamente non appena le risorse diventano
nuovamente disponibili.
Nel caso in cui il Service debba interagire direttamente con l’utente potrebbe essere necessario
incrementare la sua priorità come quella di un’Activity in foreground. Questo ci assicura che i
nostri Service non vengano terminati se non in circostanze estreme, chiaramente però a scapito della
gestione delle risorse a tempo di esecuzione, potenzialmente con un conseguente degrado generale
dell’esperienza utente.
Il cuore di un’applicazione Android: AndroidManifest.xmlL’AndroidManifest.xml è il file che definisce i contenuti e il comportamento della nostra applicazione:
all’interno di questo file sono elencate le Activity e i Service dell’applicazione, con i permessi che necessita
per funzionare correttamente.
Ogni progetto Android include un AndroidManifest.xml memorizzato nella directory principale del progetto: in
questo file XML si possono inserire nodi per ogni elemento (Activity, Service,Content Provider e così via) che
compone la nostra applicazione, impostando i permessi per determinare come questi interagiscono l’un l’altro
e con le altre applicazioni.
Come abbiamo visto ogni applicazione gira all’interno di un proprio processo Linux, per cui ci sono delle
restrizioni ben specifiche: ogni processo non può accedere alla memoria di un altro processo, e ad ogni
applicazione è assegnato uno specifico identificatore utente. Inoltre i file di un applicativo non possono essere
letti o scritti da altri applicativi: anche l’accesso a diverse operazioni critiche sono protette, e dobbiamo
specificatamente chiedere i permessi per utilizzarle. Questo tipo di richieste vanno impostate
nell’AndroidManifest.xml .
Quando l’applicazione viene installata il gestore dei pacchetti concede o non concede i privilegi a seconda di
come li abbiamo configurati nell’AndroidManifest.xml.
Tra i principali permessi che possiamo richiedere ci sono i seguenti:
•READ_CONTACTS: leggere (ma non scrivere) i dati dei contatti dell’utente.
•WRITE_CONTACTS: scrivere (ma non leggere) i dati dei contatti dell’utente
•RECEIVE_SMS: monitorare l’arrivo di messaggi SMS
•INTERNET: accedere ed utilizzare la connessione Internet
•ACCESS_FINE_LOCATION: utilizzare un accurato sistema di localizzazione come il GPS
La radice di ogni AndroidManifest.xml è il tag <manifest>: questo tag include i nodi che definiscono i
componenti dell’applicazione, l’ambiente di sicurezza, e tutto ciò che fa parte dell’applicazione. Nelle lezioni
successive vedremo come si configura correttamente questo importante file e quali strumenti possiamo
utilizzare per facilitare il nostro lavoro.
Android Virtual Device: virtualizziamo i dispositiviL’Android Virtual Device (AVD) permette agli sviluppatori di testare le loro applicazionisenza dover per
forza possedere e collegare al PC uno smartphone Android vero e proprio. Gli AVD possono essere creati
con differenti configurazioni per emulare differenti tipi di smartphone reali. L’SDK di Android non include alcun
AVD pre-installato, dunque è necessario creare almeno un device virtuale prima di poter testare le nostre
applicazioni in un emulatore.
Come vedremo in dettaglio nelle lezioni successive, ogni AVD è configurato almeno con un nome, una
versione di SDK supportata (Android 1.6, Android 2.1 e così via), un valore che indica la quantità di memoria
da riservare per la scheda SD e una risoluzione per lo schermo.
Il plugin ADT di Eclipse (nelle lezioni precedenti abbiamo visto come installarlo e come integrarlo all’interno
dell’IDE) permette di gestire come facilità gli AVD e gli emulatori. In particolare permette di lanciare
automaticamente l’emulatore all’interno dell’AVD selezionato per testare o effettuare il debug dei nostri
progetti. Ovviamente chi non volesse utilizzare Eclipse e il plugin corrispondente può controllare l’emulatore
attraverso la linea di comando (il terminale).
Resource : la gestione delle risorse in AndroidUna Resource può essere un'immagine bitmap, una stringa di testo che valorizza una etichetta o un bottone,
o può essere qualsiasi altra informazione che non sia codice e che è necessaria per il corretto
funzionamento dell’applicazione Android.
Tutte le Resource vengono compilate all’interno dell’applicazione: questo è molto utile per implementare
l’internazionalizzazione o per supportare diversi tipi di device. Le Resourcesono memorizzate e create
all'interno di una directory specifica, la directory res del nostro progetto: il compilatore delle risorse di Android
processa le risorse in base alle sotto-directory in cui sono memorizzate e in base al formato dei file.
Ad esempio i file immagine JPG o PNG dovrebbero essere memorizzati in una directory all'interno del
percorso res/drawable mentre i file XML che descrivono e configurano i layout delle schermate dovrebbero
essere memorizzate in una directory all'interno del percorsores/layout. Possiamo aggiungere alle directory
suffissi specifici per indicare una particolare lingua, un determinato orientamento dello schermo, la densità dei
pixel e molto altro ancora.
Il compilatore delle risorse comprime e impacchetta le risorse delle nostre applicazioni, e
successivamente genera una classe chiamata “R” che contiene tutti gli identificatori che possiamo utilizzare
per riferirci alle risorse del programma. Questa tecnica assicura che tutte le referenze delle Resource siano
valide e permette di risparmiare spazio non dovendo memorizzare anche le stringhe di referenza come
avviene in ambiente Java standard.
Creazione di un’applicazioneOra siamo pronti per implementare la nostra prima applicazione Android: iniziamo con il classico esempio
“Hello Word”.
Prima di creare un nuovo progetto però dobbiamo installare alcuni componenti aggiuntivinell'SDK di
Android, componenti che ci permetteranno, in fase di creazione del progetto, di selezionare un target di
riferimento per il progetto stesso. Per fare questo, come vedremo dettagliatamente nelle lezioni successive,
apriamo l' “Android SDK and AVD Manager” seguendo questo percorso dal menu di Eclipse: Window /
Android SDK and AVD Manager(per installare Eclipse e l'SDK di Android si veda la lezione I software
necessari).
Nota: se Eclipse dovesse restituire un errore si torni nel menu Windows / Preferences / Android e si verifichi
che alla voce SDK Location sia indicato effettivamente il percorso dell'SDK di Android. Se non lo fosse, lo si
cambi. Se lo fosse, si prema OK per confermare la scelta e si riapra l'Android SDK and AVD Manager come
descritto sopra.
Nella finestra che compare selezioniamo la voce Available packages del menu di sinistra, poi la voce Android
Repository nel pannello di destra e selezioniamo i componenti che vogliamo installare (per questo e per i
prossimi esempi che vedremo possiamo installare anche solo il pacchetto “SDK Platform Android 2.1, API7″).
Facciamo clic su Install selected e poi, nella finestra successiva, su Install. Il sistema installerà
automaticamente anche gli “Android SDK Platform-tools”. Ad installazione conclusa possiamo proseguire.
Figura 2: L'installazione dei componenti aggiuntivi di Android
(clic per ingrandire)
Dal menu File di Eclipse selezioniamo New / Project. Nella finestra che compare selezioniamoAndroid /
Android Project e poi clicchiamo su Next.
A questo punto appare la finestra di dialog New Android Project: con questo wizard configureremo il nuovo
progetto.
Inseriamo la stringa “HelloWord” come nome del progetto, “HelloWordApp” come nome dell’applicazione,
“com.html_it.examples” come nome del pacchetto, “HelloWordActivity” come nome dell’Activity. La stringa
che inseriamo come nome dell’applicazione è quella che comparirà nella barra del titolo dell’applicazione,
dunque in una implementazione reale bisogna avere qualche accortezza per la scelta di questo nome.
Figura 3: La finestra di configurazione dell'applicazione
Rimane da selezionare il build target per l’applicazione, scegliamo per il nostro esempio il target Android 2.1
(API level 7), e il Min SDK (nel nostro caso 7), ovvero la versione minima di Android richiesta per la nostra
applicazione.
A questo punto clicchiamo su Finish, e l’ADT genererà la struttura rappresentata nella Figura 4: questa
struttura rimane molto simile anche per applicazioni più complesse e di maggiori dimensioni rispetto
all’esempio “HelloWord”. La struttura la vedremo in dettaglio nella lezione successiva.
Figura 4: La struttura di un'applicazione Android
Struttura di un’applicazioneRiproponiamo, per comodità, la Figura 4 già vista nella lezione precedente e ne descriveremo in dettaglio le varie componenti.
Figura 4: La struttura di un’applicazione Android
Un’applicazione Android deve avere almeno tre componenti per poter funzionare:
1.Il file AndroidManifest.xml, che come abbiamo visto nelle lezioni precedenti si trova nella directory principale del progetto ed è responsabile della configurazione e del comportamento della nostra applicazione.
2.La cartella “src” che contiene il codice sorgente
3.La cartella “resource” che contiene le risorse necessarie alla nostra applicazione per un corretto funzionamento: questa cartella può contenere sottocartelle per l’organizzazione delle risorse, come ad esempio “drawable”, “raw”, “layout”, “anim” e così via
Abbiamo già introdotto il file AndroidManifest.xml, mentre il codice sorgente inizieremo a vederlo nelle
lezioni successive.
Puntualizziamo invece alcune caratteristiche della gestione delle risorse in ambiente Android: innanzitutto
dobbiamo sottolineare che Android supporta una organizzazione lineare per la cartella “res”. Questo significa
che non sono supportate sottocartelle oltre il secondo livello, ad esempio all’interno della directory “layout” (e
ovviamente all’interno delle altre sottocartelle dirette della directory “res”) il sistema non riconosce le
sottocartelle create.
Un’altra puntualizzazione necessaria riguarda le cartelle “raw” e “assets”, che se necessarie creeremo
nella cartella “res”. Queste due directory possono contenere la stessa tipologia di file, solo che quelli
contenuti nella cartella “raw” sono considerati delle risorse a tutti gli effetti, mentre i file contenuti in “assets”
no. I file contenuti in “raw” saranno localizzati e accessibili attraverso gli ID autogenerati, mentre il contenuto
della cartella “assets” è considerato come contenuto generico: questo significa per esempio che nella cartella
“assets” possiamo organizzare arbitrariamente la gerarchia di cartelle e sottocartelle, cosa che come abbiamo
visto non è permessa quando ci occupiamo delle risorse.
La cartella “layout” contiene invece alcune View della nostra applicazione: è in questa cartella che mettiamo
i file XML che definiscono le interfacce della app (invece che definirle da codice).
Le cartelle “drawable-ldpi”, “drawable-hdpi”, “drawable-mdpi” contengono immagini ed altre risorse
grafiche per differenti risoluzioni e densità degli schermi, mentre nella cartella “anim” possiamo mettere le
animazioni eventualmente utilizzate dalle nostre applicazioni. In “menu” ci saranno i descrittori XML che
definiscono la struttura dei vari menu e in “values” possiamo mettere altre risorse utilizzate dall’applicazione,
come ad esempio stili, stringhe e definizioni di colori (sempre sottoforma di descrittori XML).
Creare un dispositivo di emulazionePer eseguire il building e il debugging di una applicazione Android dobbiamo prima completare i seguenti passi:
1.Configurare un Android Virtual Device (AVD) per l’emultatore
2.Creare una configurazione di debug per il progetto (lo vedremo nella lezione successiva)
Per completare queste procedure possiamo utilizzare il plugin ADT di Eclipse: l’IDE collegherà il debugger
all’emulatore Android (o allo smartphone che usiamo per sviluppare) così potremo liberamente eseguire il
debug delle applicazione in maniera comoda e precisa.
Android Virtual Device
L’Android Virtual Device descrive il tipo di device che l’emulatore può simulare, includendo la piattaforma
Android supportata (Android 1.6, Android 2.1 e così via). La configurazione dell’AVD comprende la scelta
della dimensione dello schermo, la possibilità di utilizzare una SD card e la sua dimensione. Per creare un
AVD è necessario seguire questa procedura:
1.Lanciare l’Android SDK e AVD Manager da Eclipse cliccando sull’icona dedicata che troviamo nella toolbar (Figura 5) oppure seguendo il percorso di menu Window / Android SDK and AVD Manager;
Figura 5: Il pulsante di accesso all'Android SDK in Eclipse
2.Comparirà un dialog diviso in due parti: il menu e il pannello gestionale. Clicchiamo sulla voce“Virtual Devices” visibile nel box di sinistra: nella parte destra del dialog comparirà l’elenco degli AVD finora creati (se è il primo AVD che creiamo chiaramente la lista sarà vuota);
3.Cliccare sul pulsante “New” per creare un nuovo AVD;
4.A questo punto dobbiamo compilare i campi richiesti (Figura 6). Scegliamo un nome per l’AVD; Selezioniamo il target: ad esempio per il supporto ad Android 2.1 scegliamo la voce “Android 2.1-update – API Level 7″. Ricordiamo che i target disponibili si installano seguendo la voce “Available packages” del menu di sinistra, e selezionando le piattaforme disponibili che compaiono cliccando sulla voce “Android Repository” del pannello destro;
5.Scegliamo la capacità della card SD: l’immagine che verrà creata prenderà spazio nel nostro disco fisso, pertanto scegliamo un valore ragionevole, ad esempio 1024 Mib (il valore minimo è di 9 MiB);
6.Il passo successivo è la scelta di una skin, ovvero la modalità di visualizzazione dell’emulatore. Selezioniamo la skin “(HVGA)”, che rappresenta la visualizzazione in modalità “portrait”;
7.Clicchiamo sul pulsante “Create AVD” e attendiamo la fine del processo di creazione.
Figura 6: La creazione di un nuovo Android Virtual Device (AVD)
Finito il processo di creazione potremo vedere l’AVD che abbiamo creato nel pannello di destra “List of
existing Android Virtual Device located at …”. Se volete testare il vostro emulatore è sufficiente selezionarlo e
cliccare sul pulsante “Start” sulla destra della finestra dialog.
Configurare l’esecuzione e il debugPrima di lanciare la nostra applicazione “HelloWord” è necessario creare una configurazione di “Run” o di “Debug” per il progetto. Vediamo i passi da completare per creare una configurazione di “Debug”, quella che useremo di più in fase di sviluppo:
1.Sempre in Eclipse, nel menu principale selezioniamo il percorso Run / Debug Configurations;
2.Nell’elenco disponibile sulla parte sinistra della finestra di dialog che si apre eseguiamo un doppio click sulla voce “Android Application” per creare una nuova configurazione;
3.Cambiamo il nome della configurazione appena create da “New_configuration” a “Android Debug” (o altro nome);
4.Clicchiamo sul pulsante Browse e scegliamo il progetto che vogliamo debuggare, nel nostro caso “HelloWord”;
5.Spostiamoci sulla scheda Target e controlliamo il target associato al nostro progetto. Se lasciamo la spunta su Automatic verrà scelto in automatico il target adatto al progetto lanciato, altrimenti possiamo scegliere di spuntare la voce Manual: scegliendo questa opzione ogni volta che lanciamo un progetto con la configurazione
“Android Debug” ci verrà chiesto di selezionare un target. Questa opzione è molto utile e comoda quando dobbiamo testare la nostra app su differenti smartphone o emulatori;
6.Clicchiamo sul pulsante Apply per confermare le modifiche.
Figura 7: La configurazione del debug di un'applicazione Android
La creazione di una configurazione per il running delle app è un processo molto simile a quello che
abbiamo appena visto per la creazione della configurazione di debugging. Da un punto di vista pratico ciò che
cambia è al punto 1 della precedente lista, dove al posto della voce Run / Debug configurations dovremmo
seguire il percorso Run / Run Configurations.
Da un punto di vista funzionale invece ciò che cambia principalmente nell’utilizzare una configurazione di
running piuttosto che una di debugging è che se usiamo quella di debugging il debugger di Eclipse sarà
collegato alla nostra applicazione, facilitando il debug del nostro codice anche grazie all’utilizzo dei
breakpoint.
Utilizzando il plugin ADT di Eclipse, quando eseguiamo il running o il debugging della nostra applicazione
succede quanto segue:
1.Viene compilato il progetto corrente e convertito in un eseguibile Android (.dex);
2.Gli eseguibili e le risorse esterne della applicazione vengono organizzate in un package Android (.apk);
3.Il device virtuale selezionato viene fatto partire (se non è già stato fatto partire prima, altrimenti questo punto non viene eseguito);
4.L’applicazione viene installata nel device vituale selezionato;
5.L’applicazione viene fatta partire nel device vituale.
Eseguire test sull’emulatore e sullo smartphoneVediamo dunque come eseguire il debug della nostra applicazione di prova usando, prima, l'emulatore di Eclipse e, dopo, su un terminale reale.
Test nell'emulatore
Siamo pronti per lanciare e testare la nostra app nell'emulatore precedentemente configurato. Tutto quello
che dobbiamo fare è cliccare sul pulsante Debug ( ) che troviamo nella toolbar di Eclipse; oppure
premere il tasto F11 o scegliere la voce Debug dal menu Run.
Una volta cliccato sul pulsante Debug verrà lanciato il l’emulatore: al primo lancio è necessario aspettare un
po’ di tempo prima di poter interagire con il device virtuale, dunque aspettiamo con calma che lo startup si
concluda (anche alcuni minuti su computer meno potenti). Quando l’emulatore è pronto per l’interazione
possiamo premere e trascinare il pulsante di sblocco con il lucchetto verde finché non sblocchiamo il device
virtuale, come possiamo vedere nell’immagine seguente:
Figura 8: L'emulatore prima di essere sbloccato
Se abbiamo fatto tutto correttamente nel nostro emulatore vedremo una schermata molto simile a quella
seguente:
Figura 9: L'emulatore con la nostra applicazione di prova
Come possiamo vedere nella Figura 9, l’applicazione è molto semplice: viene visualizzato un controllo di
tipo TextView con una linea di stato, “Hello Word, Helloword!“. Abbiamo creato e testato la nostra prima
applicazione Android!
Test nello smartphone
Facciamo un ulteriore passo in avanti: dopo aver testato la nostra semplice applicazione del device virtuale,
vediamo come si comporta su un device reale.
Per procedere abbiamo bisogno di un cavo USB per collegare il nostro smartphone al PC e completare la
seguente procedura:
1.In Eclipse selezioniamo Run / Debug Configurations;
2.Clicchiamo due volte su Android Debug;
3.Clicchiamo sulla scheda Target e impostiamo Deployment Target Selection Mode suManuale“. Selezionare la voce Manual che ci permetterà di scegliere se eseguire il debug nell’emulatore o nel device;
4. Clicchiamo sul pulsante Apply;
5.Colleghiamo attraverso una porta e un cavo USB il nostro smartphone al PC.
Nel caso in cui stessimo lavorando in ambiente Linux (es. Ubuntu) è necessario eseguire qualche passaggio
ulteriore:
•Accedere alla directory platform-tools: la troviamo nella directory in cui abbiamo installato l’SDK di Android;
•Eseguiamo il “kill” del server “adb” lanciando il comando sudo ./adb kill-server;
•Riavviamo il server “adb” con il comando sudo ./adb start-server. In questo modo il server avrà i permessi necessari per accedere al device collegato al Pc;
6.Facciamo clic sul pulsante Debug per concludere la configurazione.
A questo punto comparirà la finestra Android Device Chooser, in cui vengono visualizzati i device, virtuali e/o
reali, di cui possiamo disporre nel nostro PC e che possiamo scegliere per eseguire il debug
dell’applicazione. Il nostro device deve essere abilitato per il debug attraverso la connessione USB. Per
attivare questa configurazione, selezioniamo il menuImpostazioni dello smartphone, poi la voce Applicazioni e
qui impostiamo la seguente configurazione:
1.Attiviamo l'opzione Origini sconosciute;
2.Selezioniamo la voce Sviluppo;
3.Nelle opzioni disponibili in questa sezione attiviamo le voci Debug USB e Rimani attivo: quest’ultima opzione disabilita il controllo sull’attivazione dello schermo, lasciandolo sempre attivo.
Per concludere il processo è sufficiente fare doppio clic sul device in cui si vuole eseguire l'applicativo nella
finestra Android Device Chooser.
Eseguito l’ultimo passaggio, Eclipse installerà l’applicazione Android nel device che abbiamo selezionato
dall’elenco dei device disponibili (reali o virtuali) e la eseguirà. Se abbiamo eseguito questa procedura per
l’applicazione “Hello Word” vista nella lezione precedente, nel nostro smartphone comparirà una schermata
molto simile a quella rappresentata dalla figura 9.
Rimane da sottolineare ancora una questione: ogni volta che finiamo di lavorare sullo smartphone dobbiamo
ricordarci di disabilitare le impostazioni attivate sopra. L’attivazione permanente dello schermo, se non
disabilitata, ovviamente porta ad un rapido scaricamento della batteria, mentre l’attivazione delle altre opzioni
al di fuori del contesto di sviluppo lascia aperte notevoli falle per la sicurezza del nostro device.
Definire caratteristiche e interfaccia graficaSviluppare software è un’attività complessa perché richiede diverse fasi da completare in modo attento e preciso per raggiungere pienamente il proprio obiettivo.
Nel contesto dello sviluppo mobile questo concetto è ancora più radicato: sviluppare un applicativo mobile è
un’attività che richiede particolari attenzioni perché ci muoviamo in un ambiente in cui le risorse sono limitate,
i monitor sono di piccole dimensioni e l’efficienza diventa una delle componenti fondamentali per la buona
riuscita del nostro lavoro.
In questa e nelle seguenti lezioni vedremo alcune tecniche e best practise per scrivere codice Android
efficiente e professionale e alcune linee guida per la progettazione degli applicativi. Partiamo dalle
caratteristiche e dall'interfaccia grafica.
Le caratteristiche
Supponiamo di voler sviluppare un applicativo che implementi il famoso gioco del Tris: lo chiameremo MyTris.
La struttura di questa applicazione è molto semplice, infatti possiamo immaginarla composta di cinque
elementi:
•Splash: lo splash rappresenta l’immagine visualizzata quando l’applicazione è in fase di caricamento, in cui normalmente vengono rappresentati il logo del gioco o dell’applicativo e il numero di versione. È anche molto comune la presenza di una musica di sottofondo;
•Menu: il menu permette all’utente di scegliere tra diverse opzioni, come ad esempio configurare l’applicativo, avviare il gioco, vedere i punteggi, accedere ai credits, visualizzare l’help e così via ;
•Avvio: questa schermata è quella che compare una volta avviato il gioco o l’applicativo;
•Help: il compito dell’help è quello di visualizzare le istruzioni di utilizzo del gioco o dell’applicativo, descrivendo i controlli disponibili, gli obiettivi, e nel caso dei giochi anche come si vince e il metodo con cui si calcolano i punteggi;
•Credits: in questa schermata vi saranno le informazioni sull’azienda o su chi si è occupato dello sviluppo o della distribuzione dell’applicativo: queste informazioni sono molto importanti perché ci permettono di essere contattati;
La struttura proposta per il gioco MyTris è in realtà una struttura molto tipica che ritroviamo implementata sia
in giochi sia in applicativi di altro genere, indipendentemente dalla piattaforma di sviluppo. Questo perché è
un valido modello che permette di avere una buona usabilità, una facilità d’uso ma anche flessibilità e
chiarezza.
L'interfaccia grafica
Le interfacce utente in Android possono essere create in modo procedurale o dichiarativo. Nel primo
caso si intende l’implementazione dell’interfaccia grafica nel codice: ad esempio, in un’applicazione Swing
scriviamo il codice Java per creare e manipolare tutti gli oggetti dell’interfaccia utente, come JButton, JFrame
e così via.
La creazione dichiarativa non richiede la scrittura di codice: l’esempio tipico del metodo dichiarativo è
rappresentato dalla creazione di una pagina web statica, in cui utilizziamo l’HTML per descrivere cosa
vogliamo vedere nella pagina. L’HTML è dunque dichiarativo.
Android permette la creazione di interfacce sia procedurali sia dichiarative: possiamo creare un’interfaccia
utente completamente in codice Java (metodo procedurale) oppure possiamo creare l’interfaccia utente
attraverso un descrittore XML (metodo dichiarativo). Android inoltre permette anche un approccio ibrido, in
cui si crea un’interfaccia in modo dichiarativo e la si controlla e specifica in modo procedurale (si richiama il
descrittore XML da codice e si continua a lavorare da lì).
Se guardiamo nella documentazione Android per i componenti delle interfacce utente vedremo che gli
attributi presenti nelle API Java e quelli utilizzabili negli XML dichiarativi sono gli stessi: questo dimostra che in
entrambi i casi abbiamo a disposizione le medesime possibilità. Dunque quale metodo è meglio utilizzare?
Entrambi i metodi sono soluzioni valide, anche se Google suggerisce nella maggior parte dei casi di usare
la metodologia dichiarativa perché spesso il codice XML è più corto e semplice da leggere e capire rispetto al
corrispondente codice Java, ed inoltre è molto meno probabile che cambi nelle versioni future della
piattaforma.
Specificare le attività dell’applicazioneAbbiamo quindi ragionato sulla struttura base del nostro applicativo MyTris ed abbiamo analizzato e tracciato le linee guida per la progettazione delle interfacce che potremo implementare. Il passo successivo è quello di ragionare sul “core” del nostro gioco: leActivity.
MyTris necessiterà almeno di cinque Activity, una per ogni caratteristica del gioco:
1.SplashActivity: questa sarà l’Activity lanciata di default che svolgerà il semplice compito di mostrare un layout composto molto probabilmente da una immagine, una musica di sottofondo suonata fino al caricamento della MenuActivity;
2.MenuActivity: questa Activity mette a disposizione il menu del gioco, proponendo un layout composto da diversi pulsanti, uno per ogni feature dell’applicazione. Inoltre ad ogni pulsante assoceremo un gestore per l'evento “clic pulsante”, in modo tale che una volta premuto venga lanciata l’Activity legata al pulsante stesso;
3.PlayActivity: questa Activity sarà la reale implementazione del gioco; sarà responsabile di gestire gli input dell’utente, di tenere i punteggi della partita e di gestire tutte le dinamiche del gioco che implementeremo;
4.HelpActivity: visualizzerà un testo con le spiegazioni sul funzionamento del gioco e sul calcolo dei punteggi;
5.CreditsActivity: visualizzerà un testo con le informazioni su chi ha sviluppato il prodotto e su come sia possibile contattarlo. Avrà un layout molto simile alla HelpAcvitity: probabilmente visualizzeremo il testo servendoci di un controllo TextView scrollabile;
Ogni Activity avrà la propria classe e il proprio layout memorizzato nella directoryresources: in alcuni
casi, come per le activity ScoreActivity e HelpActivity, visto che i loro compiti sono molto simili, si potrebbe
pensare di condividere uno stesso layout e di impostare il testo da visualizzare a tempo di esecuzione invece
che all’interno del layout stesso.
Possiamo inoltre servirci di schemi e wireframe per analizzare e studiare la navigabilità e l’usabilità del
gioco, per verificare eventuali problematiche e criticità e trovare le soluzioni che più si addicono alle
caratteristiche del nostro gioco.
Implementare le funzionalitàOra che abbiamo visto come progettare una tipica applicazione Android possiamo passare all’implementazione. Tenendo presenti le caratteristiche del nostro gioco teorico MyTris, vedremo in questa lezione alcuni dettagli e principi che sono alla base dello sviluppo di un’applicazione Android. Vedremo poi come metterli in pratica.
Il primo elemento che vedremo più in dettaglio è l’application context. L’application context è un elemento
centrale e importante per tutte le funzionalità disponibili al più alto livello applicativo: possiamo utilizzare
l’application context per accedere alle risorse e alle impostazioni condivise tra istanze di diverse Activity.
Una volta recuperato l’application context, ad esempio con il seguente codice:
Context context = getApplicationContext();
possiamo utilizzarlo per accedere ad un ampio insieme di caratteristiche e servizi a disposizione
dell’applicazione. Ad esempio possiamo richiamare il metodogetSharedPreferences() dell’application
context per recuperare le preferenze condivide dell’applicazione, oppure possiamo richiamare il
metodo getResources() per recuperare le risorse dell’applicazione:
String hello =
context.getResources().getString(R.string.hello);
Visto che la classe Activity deriva dalla classe Context possiamo utilizzare il riferimentothis oppure
richiamare esplicitamente l’application context.
Potremmo dunque riscrivere l’esempio precedente come segue:
String hello = getResources().getString(R.string.hello);
L’application context lo utilizziamo anche per:
1.Lanciare istanze di Activity.
2.Gestire le directory, i database e i file protetti dell’applicazione.
3.Richiamare i gestori di servizi di sistema (e.g. servizio di localizzazione).
4.Applicare e controllare i permessi a livello applicativo.
5.Richiamare gli asset dell’applicazione.
Possiamo dunque utilizzare l’application context per lanciare istanze delle Activity. Per il nostro gioco di
esempio MyTris, dovremmo implementare, ad esempio, cinque Activity, una per ogni schermata.
Oltre all’application context abbiamo a disposizione altre due opzioni per richiamare e lanciare istanze
di Activity: implementare il lancio di una Activity nel file manifest oppure lanciare un’Activity figlia da
una Activity padre per riceverne un risultato.
Per ogni applicazione Android dobbiamo definire nel file manifest una Activity di default: nel nostro caso
potrebbe essere SplashActivity, che come abbiamo visto nelle lezioni precedenti avrà il compito di
visualizzare un’immagine e di riprodurre una musica come introduzione al gioco.
Nelle prossime lezioni vedremo una serie di tutorial che ci guideranno nello sviluppo di piccole funzionalità
come la definizione dei layout, la gestione dei menu, la gestione con i form dell’input dell’utente, e molto altro
ancora.
Running sull’emulatoreDurante l’implementazione possiamo servirci dell’emulatore per testare il nostro lavoro: questo strumento è molto comodo perché ci fornisce un preciso feedback sull’andamento del progetto.
Bisogna però tenere presente che questo strumento ha dei grossi limiti: mentre possiamo testare e
verificare ad esempio la visualizzazione dei layout portrait (versione verticale) elandascape (versione
orizzontale), la navigabilità e i menu, attualmente l’emulatore non implementa tutte le caratteristiche hardware
supportate da Android, come la fotocamera, la vibrazione, i LED, l’accelerometro, e molto altro ancora.
In tutti quei casi in cui l’applicativo che dobbiamo sviluppare ha bisogno di queste caratteristiche
hardware non ci rimane altra scelta che testare il nostro lavoro direttamente su uno smartphone (la
procedura completa per testare le app su un device reale la trovate nella lezione 15).
Dopo aver opportunamente configurato il device reale potremo installare e testare la nostra
applicazione studiandone il comportamento in un contesto reale: in questo modo verifichiamo che il software
risponda effettivamente a quello che abbiamo programmato.
Lavoriamo con i LayoutIniziamo le lezioni pratiche con lo studio dei layout. I layout sono estensioni della classeViewGroup usati per posizionare i controlli delle nostre UI (User Interface): i layout possono essere nidificati permettendoci in questo modo di creare interfacce complesse usando anche combinazioni tra queste.
Android mette a disposizione dello sviluppatore alcuni semplici modelli di layout che semplificano
notevolmente la creazione delle interfacce: possiamo creare combinazioni di questi “tipi” per rendere le nostre
interfacce semplici da utilizzare e capire.
Vediamo alcune delle principali classi layout che la piattaforma ci mette a disposizione:
•TableLayout: questo tipo di layout ci permette di disporre gli oggetti View usando una griglia composta da righe e colonne, proprio come una tabella;
•LinearLayout: il LinearLayout allinea ogni View figlia sia in senso verticale sia in senso orizzontale (un layout orizzontale ha una riga di oggetti View, mentre un layout verticale è composto da una colonna di oggetti View);
•RelativeLayout: questo è il layout più flessibile tra quelli nativi perché permette di definire le posizioni di ogni oggetto View in relazione agli altri oggetti View presenti;
•FrameLayout: questa è la tipologia più semplice di layout, perché non fa altro che posizionare in ordine di inserimento tutti gli oggetti View partendo dall’angolo in alto a sinistra dello schermo. È molto comodo quando implementiamo degli swticher di immagini o delle interfacce a tab.
Vediamo come utilizzare i layout. Creiamo un progetto che chiamiamo HelloLinear (vedere le lezioni
precedenti per le istruzioni sulla creazione di un nuovo progetto Android). Una volta completato il processo di
creazione apriamo il file /res/layout/main.xml, che dovrebbe presentarsi più o meno come segue:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /></LinearLayout>
Questo file XML definisce un layout di tipo LinearLayout verticale, come indica l’attributoorientation impostato
a vertical. Il layout contiene un widget figlio di tipo TextView, sostanzialmente un oggetto che visualizza del
testo (quello contenuto dalla risorsa indicata nell’attributo text che in questo caso è impostato
su @string/hello). Il risultato di questo layout è molto simile a quello rappresentato dalla seguente figura:
Figura 10: L'emulatore di Android con un’applicazione di prova
Iniziamo a modificare questo layout: la prima cosa che facciamo è creare una nuova risorsa di tipo stringa.
Per fare questo apriamo il file /res/values/string.xml ovvero il file che contiene le definizioni di tutte le risorse
stringa. Quando lavoriamo con i file descrittori Eclipse ci fornisce, attraverso il plugin ADT, due modalità di
visualizzazione e utilizzo: una testuale e una visuale. Nella figura seguente potete vedere la modalità visuale
(la modalità testuale si attiva selezionando il tab string.xml e visualizza appunto un semplice XML
modificabile):
Figura 11: La modalità visuale delle risorse
(clic per ingrandire)
Come mostra l’immagine, è selezionata la risorsa stringa identificata dal nome “hello” che ha il valore “Hello
Word, HelloLinear!”. Questa è proprio la stringa che attualmente viene richiamata nel layout attraverso
l’identificatore-nome “hello”: questo è il motivo per cui quando lanciamo il test di questa applicazione vediamo
il seguente risultato:
Figura 12: L’interfaccia con le nuove stringhe
(clic per ingrandire)
dove il cerchio in verde evidenzia il valore stampato a video della risorsa stringa che contiene il nome
dell’applicazione (nella figura 6 è la seconda risorsa in elenco denominata “app_name” ) mentre il cerchio
rosso evidenzia il valore stampata a video della stringa “hello” vista poc’anzi. Quindi è evidente che possiamo
modificare questi valori a nostro piacimento, anche dopo la creazione del progetto Android.
Utilizzando la modalità visuale aggiungiamo una risorsa di tipo stringa: clicchiamo dunque sul
pulsante Add (v. Figura 13 qui sotto) e nella finestra che compare verifichiamo che sia selezionato il tipo di
risorsa string e clicchiamo su Ok. Concluso il processo di creazione delle risorsa possiamo procedere con
l’impostazione dei valori come rappresentato nella figura seguente:
Figura 13: Le impostazioni dei valori della nuova risorsa
(clic per ingrandire)
Salviamo il file: abbiamo così creato una nuova risorsa stringa identificata da “name” impostata sul valore
“Inserisci il tuo nome”.
Torniamo sul layout ed in particolare sul file “/res/layout/main.xml” e modifichiamolo come segue:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/name" /> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /></LinearLayout>
Abbiamo eliminato dal layout la visualizzazione della stringa identificata da “hello”, abbiamo inserito la
visualizzazione della risorsa stringa creata da noi poc’anzi identificata da “name” e abbiamo aggiunto un altro
widget, un oggetto EditText, ovvero un elemento molto simile ad una casella di testo HTML. Il risultato
finale sarà simile al seguente:
Figura 14: L’interfaccia con l’oggetto EditText
(clic per ingrandire)
La figura 14 mostra un layout molto diverso dalla versione precedente (v. figura 12). Abbiamo modificato
anche il nome dell’applicazione: come possiamo notare osservando più attentamente la figura nella barra
grigia posta nella zona superiore della schermata rappresentata non compare più la stringa “Hello Linear” ma
“HTML.IT – Applicazione 1”.
Possiamo eseguire questo tipo di esperimento con le principali tipologie di layout per vedere come si
comportano gli oggetti che inseriamo e per imparare a disporre i widget per comporre interfacce più
complesse e funzionali.
Nella prossima lezione modificheremo questo layout di esempio per implementare l’interfaccia di un semplice
form e gestirne l’invio dei dati.
Gestione dell’input: lavoriamo con i form5.2 Gestione dell’input: lavoriamo con i formAggiungiamo alla nostra applicazione Android di esempio dei moduli per gestire le interazioni con l’utente
Proseguiamo lo studio della piattaforma Android ed introduciamo la gestione dei form e dell’input utente. In
questa lezione riprenderemo il progetto introdotto nelle lezioni precedenti: modificheremo il layout per creare
un form ed impareremo a gestire l’invio dei dati inseriti.
La prima cosa da fare è modificare il layout /res/layout/main.xml come segue:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/form_intro" android:layout_marginTop="15dip" android:layout_marginBottom="25dip" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/name" /> <EditText android:id="@+id/edit_name" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/lastname"
android:layout_marginTop="15dip" /> <EditText android:id="@+id/edit_lastname" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> <Button android:id="@+id/form_button" android:layout_height="wrap_content" android:text="@string/form_button_label" android:layout_marginTop="15dip" android:layout_marginLeft="90dip" android:layout_width="130dip" /> </LinearLayout>
Lasciamo invariata la tipologia del layout: utilizzeremo nuovamente il LinearLayout. La
primaTextView inserita visualizza semplicemente un messaggio informativo che, come vedremo tra poco,
imposteremo nel file string.xml .
Successivamente creiamo due coppie di widget costituite ognuna da un controllo TextView e da un
controllo EditText (righe 16-39), per finire con un oggetto Button (righe 41-48) che attiverà l’invio del
form. Il risultato che otteniamo sarà simile al seguente:
Figura 15: Interfaccia con moduli e il bottone di invio
(clic per ingrandire)
Come mostrato nella figura 15, ciò che otteniamo è simile ad un classico form in HTML: vi sono due caselle di
testo e un bottone per l’invio del form. Prima di vedere il dettaglio del file risorse
stringa /res/values/string.xml aggiornato, soffermiamoci ancora qualche istante sul nuovo layout e sul codice
che lo gestisce.
Abbiamo introdotto alcune direttive per gestire gli spazi e i margini tra i widget, come ad
esempio: android:layout_marginTop="15dip" eandroid:layout_marginBottom="25dip" che
aggiungono, rispettivamente, un margine superiore di 15dip ed uno inferiore di 25dip (dove dip sta
per density-independent pixels, un’unità di misura astratta basata sulla densità fisica dello schermo dello
smartphone).
Inoltre abbiamo aggiunto gli attributi id ai controlli EditText e al Button:
•android:id="@+id/edit_name"
•android:id="@+id/edit_lastname"
•android:id="@+id/form_button"
Questi valori ci serviranno più avanti per identificare e richiamare questi widget da codice e poterne gestire i
valori e le azioni ad essi associate.
Abbiamo introdotto nuovi widget ai quali abbiamo dovuto associare alcune risorse stringa. Vediamo allora il
file delle risorse stringa (il file /res/values/string.xml) aggiornato:
<?xml version="1.0" encoding="utf-8"?><resources> <string name="app_name">HTML.IT - Applicazione 1</string> <string name="form_intro">Invia il form premendo sul pulsante di invio.</string> <string name="name">Inserisci il tuo nome</string> <string name="lastname">Inserisci il tuo cognome</string> <string name="form_button_label">Invia</string> <string name="label_form_name">Nome Inserito:</string> <string name="label_form_lastname">Cognome Inserito:</string></resources>
In questo caso non dovrebbe esserci nulla di nuovo o inaspettato: abbiamo definito delle risorse stringa
identificate dall’attributo name il cui valore è contenuto all’interno dei tag<string></string> e verrà
visualizzato lì dove la risorsa sarà richiamata.
Prima di analizzare il restante codice anticipiamo cosa vogliamo ottenere. Abbiamo un’Activitydi default che
crea l’interfaccia vista poc’anzi e che, attraverso il clic del pulsante Invia invierà ad un’altra Activity i dati che
l’utente inserirà nelle opportune caselle di testo, la quale li visualizzerà con un’altra opportuna interfaccia.
Passiamo dunque ad analizzare il codice della prima Activity, quella lanciata di default. Nella
cartella /src/html/it/examples/com troviamo il file HelloLinear.java ovvero il file in cui implementiamo
l’Activity di default. Analizziamo in dettaglio il codice di questo file:
package html.it.examples.com;import android.app.Activity;import android.content.Intent;
import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;public class HelloLinear extends Activity implements OnClickListener { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final Button button = (Button) findViewById(R.id.form_button); button.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch ( v.getId() ) { case R.id.form_button: final EditText edit_name = (EditText)findViewById(R.id.edit_name); final EditText edit_lastname = (EditText)findViewById(R.id.edit_lastname); Bundle bundle = new Bundle(); bundle.putString("name", edit_name.getText().toString()); bundle.putString("lastname", edit_lastname.getText().toString()); Intent form_intent = new Intent(getApplicationContext(), Form.class); form_intent.putExtras(bundle); startActivity(form_intent); break; } }}
Il metodo onCreate() (rigo 12) è chiamato quando l’Activity viene creata e lanciata. Qui impostiamo il
layout di default setContentView(R.layout.main); e attiviamo la gestione del clic sul
widget Button visto precedentemente, impostando un listener sulla Activity stessa (che infatti implementa
l’interfaccia OnClickListener).
Una classe che implementa l’interfaccia OnClickListener deve obbligatoriamente implementare il
metodo OnClick(), metodo in cui si gestisce l’azione eseguita, in questo caso il clic sul Button Invia:
soffermiamoci dunque sulla gestione dell’evento.
La prima cosa da fare (righe 23-24) è recuperare i riferimenti dei controlli EditText definiti precedentemente e
che serviranno per salvare i dati inseriti dall’utente, in questo caso il nome ed il cognome:
final EditText edit_name = (EditText)findViewById(R.id.edit_name);
final EditText edit_lastname = (EditText)findViewById(R.id.edit_lastname);
A questo punto (righe 25-27) creiamo un oggetto Bundle che utilizziamo per salvare i dati inseriti dall’utente:
Bundle bundle = new Bundle();bundle.putString("name", edit_name.getText().toString());bundle.putString("lastname", edit_lastname.getText().toString());
Utilizziamo il metodo putString() dell’oggetto bundle per salvare i dati inseriti, recuperati poi con il
metodo getText() del widget EditText.
Con i dati memorizzati nel Bundle creiamo l’Intent per la chiamata dell’Activity alla quale li vogliamo passare
(righe 28-30), nel nostro caso Form.class, associamo all’Intent il Bundle ed infine lanciamo l’Activity :
Intent form_intent = new Intent(getApplicationContext(), Form.class);form_intent.putExtras(bundle);
A questo punto l’applicativo “passerà la palla” ad una nuova Activity chiamata Form. Vediamo allora com’è
definita questa Activity:
package html.it.examples.com;import android.app.Activity;import android.os.Bundle;import android.widget.TextView;public class Form extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.form); final TextView text_name = (TextView) findViewById(R.id.view_name); final TextView text_lastname = (TextView) findViewById(R.id.view_lastname); Bundle bundle = this.getIntent().getExtras(); text_name.setText(bundle.getString("name")); text_lastname.setText(bundle.getString("lastname")); }}
Questa Activity è molto semplice: dopo aver impostato un nuovo layout (che vedremo in dettaglio a breve)
richiama nel codice i due controlli TextView in cui visualizzeremo i dati inseriti dall’utente ed inviati
dall’Activity di default attraverso il Bundle. Quindi recuperiamo i valori dal Bundle tramite il
metodo getString() e li impostiamo rispettivamente negli oggettiTextView text_name e text_lastname. Il
risultato sarà simile al seguente:
Figura 16: Interfaccia con la risposta all’invio del modulo
(clic per ingrandire)
Il layout rappresentato nella figura 11 è definito nel descrittore /res/layout/form.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/label_form_name" android:layout_marginTop="15dip" android:layout_marginBottom="10dip" /> <TextView android:id="@+id/view_name" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/label_form_lastname" android:layout_marginTop="15dip" android:layout_marginBottom="10dip" /> <TextView android:id="@+id/view_lastname" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
Come abbiamo visto nelle lezioni teoriche ogni volta che scriviamo una nuova Activitydobbiamo definirla nel
file AndroidManifest.xml, il file principale per la configurazione di ogni applicazione Android. Prima di lanciare
l’applicazione vediamo dunque come modificare l’AndroidManifest.xml per evitare di incorrere in un errore:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="html.it.examples.com" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="7" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".HelloLinear" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" />
Il codice aggiunto, che appunto dichiara l’esistenza di una nuova Activity, è quello evidenziato.
Menu e dialogIn questa lezione estenderemo ulteriormente le funzionalità della nostra applicazione Android dotandola con un classico menu per la gestione delle impostazioni.
Android supporta due tipi di menu: quelli che si attivano quando premiamo l’apposito pulsante fisico dello
smartphone e i menu di contesto, quelli che si attivano tenendo premuto il dito sullo schermo. Noi
implementeremo un esempio di menu del primo tipo, come quello rappresentato nella seguente figura:
Figura 17: Interfaccia con un pulsante Impostazioni
(clic per ingrandire)
Il menu Impostazioni si attiva premendo il pulsante Menu dell’emulatore o il corrispettivo pulsante fisico dello
smartphone. Selezionando il menu si apriranno le opzioni disponibili, rappresentate nella seguente figura:
Figura 18: Le due opzioni del menu Impostazioni
(clic per ingrandire)
Vediamo i passaggi necessari per implementare questo menu.
La prima cosa che dobbiamo fare è creare una nuova cartella risorse: /res/menu/. In questa cartella creiamo
un file XML menu.xml in cui definiamo il menu:
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/settings" android:title="@string/settings_label" android:alphabeticShortcut="@string/settings_shortcut" /></menu>
Con questo nuovo descrittore XML definiamo un menu composto da un item con identificatore uguale
a settings e valorizzato con due stringhe, una per il testo che comparirà nella voce di menu (Impostazioni,
cfr. figura 17) e una che possiamo utilizzare come shortcut. Aggiorniamo anche il file delle risorse
stringa /res/values/string.xml inserendo le nuove risorse necessarie:
<string name="settings_label">Impostazioni</string><string name="settings_title">Impostazioni</string><string name="settings_shortcut">i</string>
A questo punto dobbiamo modificare il file HelloLinear.java per legare il menu che abbiamo appena creato
all’Activity di default, in modo che quando premiamo il tasto fisico di menu dell’emulatore o dello smartphone
l’Activity di default sappia come gestire tale evento. Per fare questo aggiungiamo le seguenti
direttive import:
import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;
e implementiamo l’override del metodo onCreateOptionsMenu():
@Override
Il metodo getMenuInflater() restituisce un’istanza di MenuInflater che utilizziamo per leggere la
definizione del menu dall’XML vista poc’anzi e trasformarla in una View effettiva. Ogni volta che viene
selezionata una voce di menu viene richiamato il metodoonOptionsItemSelected() di cui implementiamo
l’override sempre nella stessa classe, proprio per gestire la selezione della voce di menu Impostazioni:
@Overridepublic boolean onOptionsItemSelected(MenuItem item) { switch ( item.getItemId() ) { case R.id.settings: startActivity(new Intent(this, Settings.class)); return true; } return false;}
Riassumiamo quanto fatto finora: abbiamo creato il menu principale e l’abbiamo associato all’Activity di
default. Questo elemento ha una voce di menu che si chiama Impostazioni: per gestire la selezione di questa
voce di menu abbiamo implementato il metodoonOptionsItemSelected() che dopo aver verificato quale
voce di menu è stata selezionata (nel nostro caso quella con identificatore uguale a R.id.settings) svolge
l’azione corrispondente, nel nostro caso lanciare l’Activity Settings che vedremo tra poco.
Android mette a disposizione degli strumenti che semplificano molto la definizione di tutte le preferenze
dell’applicativo e la visualizzazione di queste utilizzando pochissime linee di codice. Questo perché nella
maggior parte della applicazioni che svilupperemo sarà presente un menu Impostazioni o Preferenze, cioè un
menu con il quale l’utente può personalizzare alcuni comportamenti dell’applicazione.
Definiamo dunque le preferenze in un nuovo file risorsa /res/xml/settings.xml:
<?xml version="1.0" encoding="utf-8"?><PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <CheckBoxPreference android:key="item1" android:title="@string/menu_item_1" android:summary="@string/item1_summary" android:defaultValue="true" /> <CheckBoxPreference android:key="item2" android:title="@string/menu_item_2" android:summary="@string/item2_summary" android:defaultValue="true" /></PreferenceScreen>
Come mostrato nella figura 13, l’utente può scegliere di attivare/disattivare due impostazioni,Item1 e Item2,
entrambe sono due controlli di tipo CheckBoxPreference (in sostanza due widget molto simili alle
checkbox dell’HTML). Anche in questo caso dobbiamo aggiornare il file risorsa /res/values/string.xml per le
valorizzazioni delle voci di menu delle preferenze:
<string name="menu_item_1">Item 1</string><string name="menu_item_2">Item 2</string><string name="item1_summary">Summary Item 1</string><string name="item2_summary">Summary Item 2</string>
Rimane da vedere la definizione della classe Settings.java:
package html.it.examples.com; import android.os.Bundle;import android.preference.PreferenceActivity; public class Settings extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); }}
Questa Activity estende PreferenceActivity e richiama il metodo addPreferencesFromResource():
questo legge le definizioni delle preferenze dall’XML passato come parametro (R.xml.settings) e
permette di creare le viste corrispondenti nell’Activity corrente.
Non dobbiamo dimenticare di inserire la nuova Activity nel file di configurazioneAndroidManifest.xml, nel
quale aggiungiamo il seguente codice:
<activity android:name=<code>".Settings"</code> android:label=<code>"@string/settings_title"</code>></activity>
Lanciamo nuovamente l’applicazione, premiamo il pulsante del menu, selezioniamoImpostazioni e cambiamo
i valori delle voci Item1 e Item2: se proviamo ad uscire dal programma e poi a rientrarci, vedremo che le
voci di menu delle preferenze sono nuovamente entrambe attive, indifferentemente dalle nostre scelte
precedenti.
Questo succede perché non abbiamo gestito e memorizzati i valori delle scelte effettuate dall’utente: questo
argomento esula dal carattere introduttivo di queste lezioni, ma per ora possiamo considera che questi valori
potrebbero essere memorizzati come dati locali dell’applicativo.
Gestione della localizzazioneI servizi di localizzazione in Android si basano su due API: quella del mapping e quella dellalocation. Queste API sono divise in due pacchetti separati ed indipendenti, rispettivamentecom.google.android.maps e android.location: l’API del mapping fornisce strumenti che facilitano la visualizzazione e la manipolazione di una mappa, come ad esempio la gestione dello zoom e cambiare la modalità di visualizzazione (vista satellite, street view, ecc.), mentre l’API location mette a disposizione strumenti per la gestione del GPS (Global Position System) e dei dati di localizzazione in tempo reale.
In questa lezione implementeremo un semplice servizio che visualizzerà alcune informazioni circa le
coordinate geografiche che simuleremo ed invieremo all’emulatore.
Modifichiamo il file /res/menu/menu.xml aggiungendo il codice seguente:
<item android:id="@+id/where_am_i" android:title="@string/where_am_i_label" android:alphabeticShortcut="@string/where_am_i_shortcut" />
con il quale inseriamo una nuova voce di menu per accedere all’Activity che implementeremo tra poco.
Chiaramente dobbiamo anche aggiornare il file delle risorse stringa/res/values/string.xml:
<string name="where_am_i_label">Dove Sono?</string><string name="where_am_i_title">Dove Sono</string><string name="where_am_i_shortcut">w</string>
A questo punto creaimo un nuovo file descrittore XML /res/layout/where.xml per la generazione del layout
della nuova Activity:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_height="wrap_content" android:text="La locazione rilevata è:" android:layout_width="fill_parent" android:textSize="16px" android:textStyle="bold" android:gravity="center_horizontal" android:layout_marginTop="10dip" android:layout_marginBottom="10dip" /> <EditText android:layout_height="wrap_content" android:text="" android:layout_width="fill_parent" android:id="@+id/editTextShowLocation" android:lines="10" android:gravity="top"/> <Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/buttonGetLocation" android:text="Carica Locazione" android:textSize="15px" android:textStyle="bold" android:layout_marginTop="10dip" /> </LinearLayout>
Il layout è molto semplice: è composto da una posto da una TextView per la visualizzazione di un testo
introduttivo, un widget EditText per la visualizzazione dei dati e un Button per il caricamento dei dati. Il
risultato sarà simile al seguente:
Figura 19: Interfaccia con i dati di localizzazione
(clic per ingrandire)
Come rappresentato nella figura 19, nel widget EditText visualizziamo la data odierna, lo strumento che ci
fornisce i dati (GPS) e alcune informazioni relative alla posizione rilevata: longitudine, latitudine, altitudine,
accuratezza.
Vediamo in dettaglio il codice della classe Where.java che implementa l’Activity:
package html.it.examples.com; import android.app.Activity;import android.content.Context;import android.location.Location;import android.location.LocationListener;import android.location.LocationManager;import android.os.Bundle;import android.text.format.DateFormat;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText; public class Where extends Activity { private EditText editText; private Button buttonLoad; private LocationManager lManager; private LocationListener lListener; private Location location; @Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.where); editText = (EditText) findViewById(R.id.editText); buttonLoad = (Button) findViewById(R.id.buttonLoad); buttonLoad.setOnClickListener(new OnClickListener() { public void onClick(View v) { buttonLoadClick(); } }); } private void getCurrentLocation() { lManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); lListener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } @Override public void onLocationChanged(Location loc) { // TODO Auto-generated method stub location = loc; } }; lManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, lListener); } private void buttonLoadClick() { this.getCurrentLocation(); if ( location != null ) {
lManager.removeUpdates(lListener); String provider = location.getProvider(); String data = DateFormat.format("dd/MM/yyyy", location.getTime()).toString(); String longitude = "Longitudine: " + location.getLongitude(); String latitude = "Latitudine: " + location.getLatitude(); String altitudine = "Altitudine: " + location.getAltitude(); String accuracy = "Precisione: " + location.getAccuracy(); editText.setText("Oggi è il " + data + "nn" + "Informazioni fornite da: " + provider + "nn" + longitude + "n" + latitude + "n" + altitudine + "n" + accuracy + "n"); } else { editText.setText("Impossibile determinare la locazione!"); } }}
Recuperiamo i riferimenti delle risorse EditText e Button, ed impostiamo su quest’ultima unlistener per
gestire l’azione associata al clic del bottone:
editText = (EditText) findViewById(R.id.editText);buttonLoad = (Button) findViewById(R.id.buttonLoad);buttonLoad.setOnClickListener(new OnClickListener() { public void onClick(View v) { buttonLoadClick(); }});
Ogni volta che premiamo il bottone Carica Locazione vengono caricati i dati che simuliamo ed inviamo
attraverso la scheda di Eclipse per la gestione dei controlli dell’emulatore, chiamata appunto Emulator
Control.
Per aprire la vista Emulator Control entriamo nella perspective DDMS (Dalvik Debug Monitor Server) che
fornisce strumenti utili per il debugging delle applicazioni Android. Per selezionare la perspective DDMS
dobbiamo seguire dal menu di Eclipse il percorso Window / Open Perspective / Other / DDMS.
Il risultato sarà simile al seguente:
Figura 20: La perspective DDMS e i controlli di location
(clic per ingrandire)
Come mostrato in figura 20, nella scheda Devices selezioniamo l’emulatore al quale vogliamo inviare i dati
GPS simulati (chiaramente nel caso in cui fosse collegato e opportunamente configurato un device reale
potremmo anche selezionare questo). Una volta selezionato il device si attiveranno i controlli di locazione per
l’inserimento dei dati: nella scheda a tab denominata appunto Emulator Control selezioniamo
l’opzione Decimal, inseriamo le coordinate per la longitudine, quella per la latitudine, e premiamo il
pulsante Send per inviare i dati appena inseriti nel device selezionato precedentemente.
A questo punto torniamo sull’emulatore: premiamo il pulsante Carica Locazione. Il risultato sarà molto simile a
quanto rappresentato in figura 20.
Ogni volta che premiamo e attiviamo il pulsante Carica Locazione viene richiamata la
funzionebuttonLoadClick(). Questa funzione utilizza i metodi messi a disposizione dalla
classeLocation per recuperare le informazioni che rappresentiamo nel widget EditText:
String provider = location.getProvider();String data = DateFormat.format("dd/MM/yyyy", location.getTime()).toString();String longitude = "Longitudine: " + location.getLongitude();String latitude = "Latitudine: " + location.getLatitude();String altitudine = "Altitudine: " + location.getAltitude();String accuracy = "Precisione: " + location.getAccuracy(); editText.setText("Oggi è il " + data + "nn"+ "Informazioni fornite da: " + provider + "nn"+ longitude + "n" + latitude + "n" + altitudine + "n"+ accuracy + "n");
Richiamiamo il metodo setText() del controllo EditText al quale passiamo i dati raccolti, come ad
esempio location.getLongitudine() e location.getLatitudine(), che sono proprio le coordinate
che abbiamo inserito nella scheda Emulator Control.
Android e le applicazioni di reteLe applicazioni che svilupperemo in ambito mobile saranno quasi sempre dotate di accesso ad Internet: per consultare notizie, per informarsi sul tempo atmosferico, per leggere le email, per rimanere in contatto con i proprio amici attraverso i social network o effettuare chiamate VoIP per risparmiare sulle telefonate.
In questa lezione vedremo come fornire alla nostra applicazione d’esempio la connettività ad Internet e come
sfruttare la piattaforma Android per implementare un semplice lettore di feed RSS (Really Simple
Syndication).
Per accedere ai servizi di rete su un device Android dobbiamo avere i permessi appropriati. Una app Android
infatti può utilizzare la maggior parte dei servizi di rete solo se nel proprio file di
configurazioni AndroidManifest.xml vi sono le appropriate impostazioni.
La prima cosa che facciamo dunque è modificare il file AndroidManifest.xml della nostra applicazione
d’esempio aggiungendo i permessi per l’utilizzo di Internet:
<uses-permission android:name="android.permission.INTERNET"
Aggiungiamo una voce di menu al menu principale dell’applicazione per poter accedere al servizio RSS.
Modifichiamo quindi il file /res/menu/menu.xml aggiungendo il seguente codice:
<item android:id="@+id/rss" android:title="@string/rss_label" android:alphabeticShortcut="@string/rss_shortcut" />
Aggiungiamo le nuove risorse stringa nel file /res/values/strings.xml per la voce di menu appena inserita:
<string name="rss_label">RSS</string><string name="rss_title">RSS Feed</string><string name="rss_shortcut">r</string>
Il risultato che otterremo sarà simile a quanta rappresentato in figura 16:
Figura 21: L’applicazione con un pulsante per leggere gli RSS
(clic per ingrandire)
L’implementazione del lettore di RSS è divisa in due Activity diverse: la prima (RSS.java) è quella in cui
impostiamo il feed da leggere e il layout principale, la seconda (RSSItem.java) è quella che genera la lista di
elementi pubblicati nel feed con il relativo layout.
Vediamo in dettaglio il codice della prima Activity RSS.java:
package html.it.examples.com; import android.app.Activity;import android.os.Bundle;import java.util.ArrayList;import android.widget.ArrayAdapter;import android.widget.ListView; public class RSS extends Activity { String feedUrl = ""; ListView rssListView = null; ArrayList<RSSItem> RSSItems = new ArrayList<RSSItem>(); ArrayAdapter<RSSItem> array_adapter = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rssmain); feedUrl = "http://feeds.feedburner.com/Blogrammazione/"; refreshRSSList(); rssListView = (ListView) findViewById(R.id.rssListView); array_adapter = new ArrayAdapter<RSSItem>(this, R.layout.list_item, RSSItems); rssListView.setAdapter(array_adapter); refreshRSSList(); } private void refreshRSSList() { ArrayList<RSSItem> newItems = RSSItem.getRSSItems(feedUrl); RSSItems.clear(); RSSItems.addAll(newItems); } }
Inizialmente definiamo nella classe alcune variabili:
String feedUrl = "";ListView rssListView = null;ArrayList<RSSItem> RSSItems = new ArrayList<RSSItem>();ArrayAdapter<RSSItem> array_adapter = null;
La variabile feedUrl di tipo stringa ci servirà per memorizzare l’URL del feed da leggere;rssListView è la
variabile che conterrà il riferimento al widget di tipo ListView contenuto nel descrittore XML che definisce il
layout della lista di elementi letti dal feed; RSSItems è una struttura di tipo ArrayList che conterrà la lista
degli elementi del feed (ognuno caratterizzato da un titolo, una descrizione, una data di pubblicazione e un
link); array_adapter è una variabile che conterrà un oggetto di tipo ArrayAdapter che, come vedremo
più in dettaglio tra qualche istante, permette di legare degli oggetti anche di tipo arbitrario contenuti in un
array con un determinato layout più o meno complesso.
All’interno del metodo principale dell’Activity onCreate(), impostiamo il feed che leggeremo, richiamiamo il
metodo refreshRSSList() e creiamo l’Array Adapter passando come parametri il contesto attuale
(mediante il riferimento this), il file descrittore XML per il layout della lista (R.layout.list_item) ed
infine il riferimento che conterrà la lista di oggettiRSSItem:
feedUrl = "http://feeds.feedburner.com/Blogrammazione/"; refressRssList(); rssListView = (ListView) findViewById(R.id.rssListView); array_adapter = new ArrayAdapter<RSSItem>(this, R.layout.list_item, RSSItems);rssListView.setAdapter(array_adapter); refreshRSSList();
La funzione refreshRSSList recupera e aggiorna la lista di item letti dal feed e aggiunge questi elementi
all’ArrayList che contiene tutte le voci del feed:
private void refreshRSSList() { ArrayList<RSSItem> newItems = RSSItem.getRSSItems(feedUrl); RSSItems.clear(); RSSItems.addAll(newItems); }
Il file descrittore XML /res/layout/rssitem.xml per il layout di questa Activity è davvero molto semplice, visto
che contiene solo un widget di tipo ListView:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical">
<ListView android:id="@+id/rssListView" android:layout_width="fill_parent" android:layout_height="wrap_content" /></LinearLayout>
La seconda Activity, RSSItem.java, legge ogni elemento del feed e costruisce la lista di itemche vengono
visualizzati nella precedente RSS.java:
package html.it.examples.com; import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date; import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.NodeList; public class RSSItem { private String title; private String description; private Date date; private String link; public RSSItem(String title, String description, Date pubDate, String link) { this.title = title; this.description = description; this.date = pubDate; this.link = link; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description;
} public Date getPubDate() { return date; } public void setPubDate(Date pubDate) { this.date = pubDate; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } @Override public String toString() { SimpleDateFormat sdf = new SimpleDateFormat("hh:mm - MM/dd/yy"); String result = getTitle() + " ( " + sdf.format(this.getPubDate()) + " )"; return result; } public static ArrayList<RSSItem> getRSSItems(String feedUrl) { ArrayList<RSSItem> rssItems = new ArrayList<RSSItem>(); try { URL url = new URL(feedUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream is = conn.getInputStream(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(is); Element element = document.getDocumentElement();
NodeList nodeList = element.getElementsByTagName("item"); if (nodeList.getLength() > 0) { for (int i = 0; i < nodeList.getLength(); i++) { Element entry = (Element) nodeList.item(i); Element _titleE = (Element)entry.getElementsByTagName("title").item(0); Element _descriptionE = (Element)entry.getElementsByTagName("description").item(0); Element _pubDateE = (Element) entry.getElementsByTagName("pubDate").item(0); Element _linkE = (Element) entry.getElementsByTagName("link").item(0); String _title = _titleE.getFirstChild().getNodeValue(); String _description = _descriptionE.getFirstChild().getNodeValue(); Date _pubDate = new Date(_pubDateE.getFirstChild().getNodeValue()); String _link = _linkE.getFirstChild().getNodeValue(); RSSItem rssItem = new RSSItem(_title, _description, _pubDate, _link); rssItems.add(rssItem); } } } } catch (Exception e) { e.printStackTrace(); } return rssItems; }}
Questa Activity genera gli item dell’RSS impostato precedentemente: ogni oggetto RSSItem ha un titolo, una
descrizione, una data di pubblicazione e un link; per ogni attributo sono inoltre disponibili i classici
metodi setter e getter.
Il cuore dell’Activity è il metodo getRSSItem(): qui apriamo una connessione URL con il server e
recuperiamo i dati dell’RSS. Se la connessione è andata a buon fine allora utilizziamo
il DocumentBuilderFactory e il DocumentBuilder per effettuare il parsing dell’XML:
URL url = new URL(feedUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream is = conn.getInputStream(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(is); Element element = document.getDocumentElement();
Con il metodo getElementsByTagName() della classe Element recuperiamo tutti gli
elementiitem contenuti nell’RSS (corrispondenti ai tag <item></item> nei dati XML) e li salviamo in un
oggetto di tipo NodeList. Effettuiamo un ciclo for su tutti i nodi dell’oggetto NodeListcreando un
oggetto RSSItem per ogni elemento presente, recuperiamo le informazioni dell’item (titolo, descrizione, data
di pubblicazione e link) e lo aggiungiamo all’ArrayList:
NodeList nodeList = element.getElementsByTagName("item"); if ( nodeList.getLength() > 0 ) { for ( int i = 0; i < nodeList.getLength(); i++ ) { Element entry = (Element) nodeList.item(i); Element _titleE = (Element)entry.getElementsByTagName("title").item(0); Element _descriptionE = (Element)entry.getElementsByTagName("description").item(0); Element _pubDateE = (Element) entry.getElementsByTagName("pubDate").item(0); Element _linkE = (Element) entry.getElementsByTagName("link").item(0); String _title = _titleE.getFirstChild().getNodeValue(); String _description = _descriptionE.getFirstChild().getNodeValue(); Date _pubDate = new Date(_pubDateE.getFirstChild().getNodeValue()); String _link = _linkE.getFirstChild().getNodeValue(); RSSItem rssItem = new RSSItem(_title, _description, _pubDate, _link); rssItems.add(rssItem); }}
Infine viene restituito l’oggetto ArrayList con tutti gli item del feed RSS analizzati e memorizzati.
Anche il file descrittore XML per il layout da utilizzare per ogni item dell’RSS è molto semplice:
<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp" android:textSize="13sp" android:autoLink="all" >
Utilizziamo solo un widget TextView per la visualizzazione dei dati di ogni item dell’RSS. A questo
proposito possiamo notare che abbiamo sovrascritto il metodo toString() per gli oggetti RSSItem, in
modo che la stampa di un elemento di questo tipo permetta di visualizzarne il titolo e la data di pubblicazione,
come mostrato nella figura seguente:
Figura 22: L’applicazione che legge i feed RSS
(clic per ingrandire)