Anda di halaman 1dari 10

Programmazione Android A cura di Carlo Pelliccia

Lezione 3

Le attivit
Le applicazioni Android, come si accennato durante la prima lezione, si compongono di quattro mattoni fondamentali: le attivit (activity), i servizi (service), i broadcast receiver ed i content provider. Ogni applicazione formata da uno o pi di questi mattoni. Non detto che li contenga tutti: ad esempio potrebbe essere costituita da due attivit e da un servizio, senza avere n broadcast receiver n content provider. Nella stragrande maggioranza dei casi, comunque, le applicazioni comprendono almeno unattivit. Le attivit, di conseguenza, sono il pi fondamentale dei componenti di base delle applicazioni Android. Cos unattivit Stando alla documentazione ufficiale, unattivit una singola e precisa cosa che lutente pu fare . Proviamo ad indagare le implicazioni di questa affermazione. Partiamo dal fatto che lutente, per fare qualcosa, deve interagire con il dispositivo. Domandiamoci come avvenga, nel caso di uno smartphone, linterazione tra luomo e la macchina. Un ruolo essenziale, naturalmente, svolto dai meccanismi di input come la tastiera ed il touchscreen, che permettono allutente di specificare il proprio volere. Le periferiche di input, tuttavia, da sole non bastano. Affinch lutente sappia cosa pu fare e come debba farlo, ma anche affinch il software possa mostrare allutente il risultato elaborato, necessario un canale aggiuntivo. Nella maggior parte dei casi questo canale il display. Nella superficie dello schermo il software disegna tutti quegli oggetti con cui lutente pu interagire (bottoni, men, campi di testo), e sempre sullo schermo viene presentato il risultato dellelaborazione richiesta. Il ragionamento ci porta alla conclusione che, per fare qualcosa con il dispositivo, necessario usare lo schermo. Esiste perci un parallelo tra il concetto di attivit, in Android, e quello di finestra, in un sistema desktop, bench non siano esattamente la stessa cosa. In generale, ad ogni modo, possiamo assumere con tranquillit che le attivit sono quei componenti di unapplicazione Android che fanno uso del display e che interagiscono con lutente. Dal punto di vista del programmatore, poi, possiamo spingerci oltre e semplificare ulteriormente. In maniera pi pragmatica, unattivit una classe che estende android.app.Activity. Lautore del codice, realizzando lattivit, si serve dei metodi ereditati da Activity per controllare cosa appare nel display, per assorbire gli input dellutente, per intercettare i cambi di stato e per interagire con il sistema sottostante. Ciclo di vita di unattivit In un sistema desktop il monitor sufficientemente spazioso da poter mostrare pi finestre simultaneamente. Perci non affatto raro lavorare con pi programmi contemporaneamente attivi, le cui finestre vengono affiancate o sovrapposte. Gli smartphone, invece, funzionano diversamente. Prima di tutto il display piccolo, e pertanto ha poco senso affiancare due o pi finestre di applicazioni differenti. Poi non bisogna dimenticare che le risorse di calcolo sono modeste, e perci non buona cosa tenere simultaneamente in vita troppi programmi. Per questi motivi le attivit di Android hanno carattere di esclusivit. possibile mandare in esecuzione pi attivit simultaneamente, ma soltanto unattivit alla volta pu occupare il display. Lattivit che occupa il display in esecuzione ed interagisce direttamente con lutente. Le altre, invece, sono ibernate e tenute nascoste in sottofondo, in modo da ridurre al minimo il consumo delle risorse di calcolo. Lutente, naturalmente, pu ripristinare unattivit ibernata e riprenderla da dove laveva interrotta, riportandola in primo piano. Lattivit dalla quale si sta allontanando, invece, sar ibernata e mandata in sottofondo al posto di quella ripristinata. Il cambio di attivit pu anche avvenire a causa di un evento esterno. Il caso pi ricorrente quello della telefonata in arrivo: se il telefono squilla mentre si sta usando la calcolatrice, questultima sar automaticamente ibernata e mandata in sottofondo. Lutente, conclusa la chiamata, potr richiamare lattivit interrotta e riportarla in vita, riprendendo i calcoli esattamente da dove li aveva interrotti.

Programmazione Android Lezione 3 Le attivit

Siccome le attivit ibernate, in termini di risorse di calcolo, non consumano nulla, in Android il concetto di chiusura delle attivit secondario e tenuto nascosto allutente. Ci, di solito, spiazza chi al suo primo confronto con la programmazione dei dispositivi portatili. Le attivit di Android non dispongono di un bottone x , o di un tasto equivalente, con il quale possibile terminarle. Lutente, di conseguenza, non pu chiudere unattivit, ma pu solo mandarla in sottofondo. Questo, comunque, non significa che le attivit non muoiano mai, anzi! Per prima cosa le attivit possono morire spontaneamente, perch hanno terminato i loro compiti. Insomma, anche se il sistema non ci fornisce automaticamente un bottone chiudi , possiamo sempre includerlo noi nelle nostre applicazioni. In alternativa, la distruzione delle attivit completamente demandata al sistema. I casi in cui unattivit pu terminare sono due: Lattivit ibernata ed il sistema, arbitrariamente, decide che non pi utile e perci la distrugge. Il sistema a corto di memoria, e per recuperare spazio inizia ad uccidere bruscamente le attivit in sottofondo.

Esistono poi dei task manager di terze parti che permettono di uccidere le attivit in sottofondo, ma non sono previsti nel sistema di base. I differenti passaggi di stato di unattivit attraversano alcuni metodi della classe Activity che, come programmatori, possiamo ridefinire per intercettare gli eventi di nostro interesse.

Figura 1 - Ciclo di vita di un'attivit.

Pagina 2

Programmazione Android Lezione 3 Le attivit

La figura illustra la sequenza di chiamate ai metodi di Activity eseguite durante i passaggi di stato dellattivit. Entriamo nel dettaglio: protected void onCreate(android.os.Bundle savedInstanceState) Richiamato non appena lattivit viene creata. Largomento savedInstanceState serve per riportare un eventuale stato dellattivit salvato in precedenza da unaltra istanza che stata terminata. Largomento null nel caso in cui lattivit non abbia uno stato salvato. protected void onRestart() Richiamato per segnalare che lattivit sta venendo riavviata dopo essere stata precedentemente arrestata. protected void onStart() Richiamato per segnalare che lattivit sta per diventare visibile sullo schermo. protected void onResume() Richiamato per segnalare che lattivit sta per iniziare linterazione con lutente. protected void onPause() Richiamato per segnalare che lattivit non sta pi interagendo con lutente. protected void onStop() Richiamato per segnalare che lattivit non pi visibile sullo schermo. protected void onDestroy() Richiamato per segnalare che lapplicazione sta per essere terminata. La prassi richiede che, come prima riga di codice di ciascuno di questi metodi, si richiami limplementazione di base del metodo che si sta ridefinendo. Ad esempio:
@Override protected void onStart() { super.onStart(); // proprio codice a seguire }

importante non dimenticare questa regola, altrimenti le attivit sviluppate potrebbero non funzionare correttamente. Descrivere unattivit Dopo che si creata unattivit, la si deve registrare allinterno del descrittore dellapplicazione (il file AndroidManifest.xml) affinch il sistema sappia della sua esistenza. Per farlo si usa un tag <activity> allinterno del tag <application>:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package=" mypackage.mysubpackage " ... > <application ... >

<activity android:name=".MyActivity" ... > ... </activity>


... </application> </manifest>

Pagina 3

Programmazione Android Lezione 3 Le attivit

Con lattributo android:name si specifica il nome della classe registrata come attivit. Si pu esprimere sia il suo percorso completo (ad esempio mypackage.mysubpackage.MyActivity) sia il nome relativo rispetto al package dichiarato nel tag <manifest> sovrastante (ad esempio .MyActivity). Altri attributi possono opzionalmente essere inseriti nel tag <activity>, allo scopo di meglio dettagliare lattivit che si sta registrando. Tra le tante cose che si possono fare, una delle pi importanti quella di attribuire una label, cio unetichetta, allattivit. Si tratta, sostanzialmente, di un titolo che il sistema user per riferirsi allattivit e per presentarla allutente. Lattributo da utilizzare android:label. Come si spiegato nella lezione precedente, in casi come questo possibile sia scrivere la stringa direttamente nellXML sia fare riferimento ad una stringa memorizzata in un file strings.xml sotto la directory res/values. Nel primo caso, quindi, si user una formula del tipo:
<activity android:name=".MyActivity" android:label="La mia attivit">

Nel secondo caso, invece, si far alla seguente maniera:


<activity android:name=".MyActivity" android:label="@string/my_activity_label">

Un altro attributo spesso usato con il tag <activity> android:icon, che permette di specificare unicona per lattivit. In questo caso si usa sempre il riferimento ad una immagine presente nella cartella res/drawable, qualcosa come:
<activity android:name=".MyActivity" android:icon="@drawable/my_activity_icon">

Se non si specifica alcuna icona, lattivit eredita automaticamente licona definita nel sovrastante tag <application>. Allinterno della coppia di tag <activity> </activity>, invece, possono essere allacciate delle relazioni particolari fra lattivit e lapplicazione e fra lattivit ed il sistema. In particolar modo, possibile collegare allattivit un intent-filter:
<activity ... > <intent-filter> ... </intent-filter> </activity>

Nel dizionario di Android, un intent la descrizione di unoperazione che deve essere eseguita . Pi semplicemente, gli intent sono dei messaggi che il sistema manda ad unapplicazione quando si aspetta che questa faccia qualcosa. Di come funzionano gli intent e di cosa si compongono torneremo a parlare in seguito. Per ora ci basta sapere che le attivit, attraverso un intent-filter, possono essere attivate in risposta ad uno specifico evento. Gli intent-filter accettano figli di tre tipi: <action android:name="nome-azione"> Individua gli intent che richiedono lazione specificata. <category android:name="nome-categoria"> Individua gli intent che appartengono alla categoria specificata.

<data android:mimeType="nome-tipo-mime">
Pagina 4

Programmazione Android Lezione 3 Le attivit

<data android:scheme="nome-schema-url"> Individua gli intent che portano dati del tipo specificato. Le azioni, le categorie ed i tipi di dato che possono essere usati sono, naturalmente, moltissimi. Per ora ci interessa sapere che unattivit dotata di un intent-filter che include lazione android.intent.action.MAIN e la categoria android.intent.category.LAUNCHER viene identificata come lattivit principale dellapplicazione. Ci significa che lapplicazione sar elencata nel men di sistema e che, quando lutente lavvier, sar lanciata proprio lattivit marcata in tale maniera. Ecco perch, in tutti gli esempi dei mesi precedenti, abbiamo sempre usato una formulazione del tipo:
<activity android:name=".MyActivity" ... > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>

Oltre allattivit principale, possiamo registrare in AndroidManifest.xml quante attivit vogliamo, da lanciare secondo necessit, come vedremo tra due paragrafi. ActivityDemo Fermiamoci un attimo con la teoria e mettiamo insieme in un esempio pratico i concetti appresi finora. Lo scopo dimostrare il ciclo di vita delle attivit, attraverso una activity che registri in un log tutti i suoi cambi di stato. Creiamo il progetto ActivityDemo, con package di riferimento example.activitydemo, ed inseriamo al suo interno la seguente omonima attivit:
package example.activitydemo; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class ActivityDemoActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i("ActivityDemo", "Richiamato onCreate() con bundle " + savedInstanceState); } @Override protected void onRestart() { super.onRestart(); Log.i("ActivityDemo", "Richiamato onRestart()"); } @Override protected void onStart() { super.onStart(); Log.i("ActivityDemo", "Richiamato onStart()"); } @Override protected void onResume() { super.onResume(); Log.i("ActivityDemo", "Richiamato onResume()"); } @Override protected void onPause() { super.onPause(); Log.i("ActivityDemo", "Richiamato onPause()"); }

Pagina 5

Programmazione Android Lezione 3 Le attivit


@Override protected void onStop() { super.onStop(); Log.i("ActivityDemo", "Richiamato onStop()"); } @Override protected void onDestroy() { super.onDestroy(); Log.i("ActivityDemo", "Richiamato onDestroy()"); } }

Questo codice, oltre a mostrarci la prassi corretta da applicare quando si ridefiniscono i metodi che intercettano i cambi di stato dellattivit, ci fa fare conoscenza con la classe android.util.Log. Come facile intuire, la classe contiene dei metodi statici per scrivere nel log di sistema. Il metodo i(), usato nellesempio, salva delle righe di log di livello INFO. Altri metodi disponibili sono v() per il livello VERBOSE, d() per il livello DEBUG, w() per il livello WARN, ed e() per il livello ERROR. Registriamo lattivit nel manifesto dellapplicazione, marcandola come attivit principale di lancio:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="example.activitydemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".ActivityDemoActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

Non dimentichiamo di includere un file res/values/strings.xml con le risorse riferite nel manifesto:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">ActivityDemo</string> </resources>

Lapplicazione ora pronta per essere avviata. Lanciate lemulatore e fate qualche prova. Mandate lattivit in secondo piano, magari azionando qualche altra applicazione fra quelle disponibili nel sistema. Quindi date unocchiata ai log emessi, per verificare il ciclo di vita dellattivit. Usando Eclipse i log possono essere consultati nella prospettiva di lavoro chiamata DDMS , nella scheda LogCat .

Pagina 6

Programmazione Android Lezione 3 Le attivit

Figura 2 - Nella scheda LogCat possibile seguire i cambi di stato dell'applicazione.

Sotto-attivit Come spiegato in apertura, unapplicazione Android pu contenere pi di unattivit. In questo caso una soltanto sar marcata come attivit principale di lancio. Le altre saranno invece delle sottoattivit, che lattivit principale potr lanciare quando ce n bisogno. Realizzare una sotto-attivit semplice tanto quanto realizzare lattivit principale: ancora una volta sufficiente estendere android.app.Activity. Le attivit secondarie vanno poi registrate nel file AndroidManifest.xml, senza per applicare lintent-filter con lazione e la categoria usate invece dallattivit principale. Lattivit principale pu lanciare delle sotto-attivit ricorrendo al metodo startActivity(). Questo accetta come argomento un oggetto di tipo android.content.Intent che, come facile intuire, rappresenta un intent. Con questo intent bisogna esprimere quale sotto-attivit deve essere avviata. Immaginiamo di voler lanciare la sotto-attivit rappresentata dalla classe MySubActivity. Tutto quello che dovremo fare, dallinterno dellattivit principale, formulare unistruzione del tipo:
startActivity(new Intent(this, new MySubActivity));

La sotto-attivit verr lanciata e prender lo schermo al posto di quella principale. SubActivityDemo Mettiamo in pratica quanto descritto nel paragrafo precedente. Il progetto si chiama SubActivityDemo01, ed il package di riferimento example.subactivitydemo01. Allinterno del package andremo ad inserire due attivit: MainActivity e SubActivity. La prima, come il suo nome lascia intendere, sar poi registrata come attivit principale e conterr un tasto che permetter il lancio della seconda. SubActivity conterr invece un tasto per poter essere chiusa e favorire cos il ritorno allattivit principale. Cominciamo con MainActivity:
package example.subactivitydemo01; import import import import import android.app.Activity; android.content.Intent; android.os.Bundle; android.view.View; android.widget.Button;

public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Button button = new Button(this); button.setText("Lancia SubActivity"); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startSubActivity(); } }); setContentView(button); } private void startSubActivity() {

Pagina 7

Programmazione Android Lezione 3 Le attivit


Intent intent = new Intent(this, SubActivity.class); startActivity(intent); } }

Quanto spiegato nel paragrafo precedente stato direttamente messo in pratica allinterno del metodo startSubActivity(). Andiamo quindi a studiare il codice di SubActivity:
package example.subactivitydemo; import import import import android.app.Activity; android.os.Bundle; android.view.View; android.widget.Button;

public class SubActivity extends Activity { @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); } }

Da questo codice apprendiamo una nozione nuova: unattivit, sia principale sia secondaria, pu terminare e chiudersi spontaneamente invocando il proprio metodo finish(). Registriamo adesso le due attivit nel descrittore dellapplicazione:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="example.subactivitydemo01" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SubActivity" android:label="@string/app_name" /> </application> </manifest>

Per completare il lavoro abbiamo bisogno di un file res/values/strings.xml:


<?xml version="1.0" encoding="utf-8"?> <resources>

Pagina 8

Programmazione Android Lezione 3 Le attivit


<string name="app_name">SubActivityDemo 01</string> <string name="main_activity">MainActivity</string> <string name="sub_activity">SubActivity</string> </resources>

Abbiamo completato. Non resta che eseguire lesempio e provare il lancio e la chiusura della sottoattivit. Lanciare una activity e farsi restituire un risultato Un altro scenario possibile il lancio di una sotto-attivit che, al termine dei propri compiti, restituisca un risultato alla activity principale. Per realizzare uno schema di questo tipo, lattivit secondaria deve essere lanciata con il metodo startActivityForResults(), anzich con startActivity(). La firma del metodo, per lesattezza, : public void startActivityForResult(Intent intent, int requestCode) Il metodo, oltre alloggetto Intent che esprime quale attivit lanciare, desidera un secondo argomento, di tipo int. Si tratta del codice della richiesta, che sar poi restituito insieme con la risposta. Ad esempio:
Intent intent = new Intent(this, SubActivity.class); startActivityForResult(intent, 10);

La sotto-attivit sar a questo punto lanciata. Prima di terminare, la sotto-attivit pu stabilire di restituire un risultato alla attivit chiamante invocando il metodo setResult(), che esiste in due diverse varianti: public void setResult(int resultCode) public void setResult(int resultCode, Intent data) Nel primo caso largomento da trasferire un codice intero, che sar poi passato alla activity principale come identificativo del risultato elaborato. Nel secondo caso, oltre al codice, si pu specificare anche un oggetto Intent da trasmettere allindietro al chiamante. Una cosa interessante che si pu fare con gli intent inserire al loro un dizionario di valori. Si tratta di coppie chiavevalore dove la chiave una stringa, mentre il valore pu essere di vari tipi. Tra i supportati ci sono i booleani, gli interi, i decimali, le stringhe e cos via. Questi valori prendono il nome di extra. Su un oggetto Intent si pu aggiungere un valore extra grazie al metodo putExtra():
intent.putExtra("messaggio", "ciao, come va?"); intent.putExtra("cliccato", true); intent.putExtra("timestamp", System.currentTimeMillis()); ...

Chi ricever lintent potr facilmente estrarre i valori, grazie ai metodi della famiglia get*Extra():
String messaggio = intent.getStringExtra("messaggio"); boolean cliccato = intent.getBooleanExtra("cliccato", false); long timestamp = intent.getLongExtra("timestamp", 0); ...

Tornando al discorso principale, una sotto-attivit prima di terminare pu impostare un codice ed un dettaglio per il proprio chiamante facendo qualcosa come:

Pagina 9

Programmazione Android Lezione 3 Le attivit


Intent data = new Intent(); data.putExtra("opzione_selezionata", opzioneSelezionata); setResult(1, data); finish();

Terminata la sotto-attivit, il sistema riprender automaticamente lactivity precedente. Il risultato sar notificato attraverso una chiamata al metodo: protected void onActivityResult(int requestCode, int resultCode, Intent data) I parametri vanno interpretati al seguente modo: requestCode: il codice di richiesta usato con il metodo startActivityForResult() per lanciare lattivit che ha restituito la risposta fornita. resultCode: il codice di risultato che la sotto-attivit ha impostato su setResult(). Se la sotto-attivit non ha mai richiamato setResult(), ad esempio perch stata annullata e chiusa con il tasto back del device, allora questo valore sar pari a 0. data: leventuale pacchetto di dati aggiuntivi impostato dalla sotto-attivit chiamando setResult(). Se assente, largomento sar null.

Allinterno dellattivit principale, quindi, possiamo ridefinire il metodo onActivityResult() per intercettare i risultati in arrivo dalle sotto-attivit lanciate. Ad esempio:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SUB_ACTIVITY_REQUEST_CODE) { if (resultCode == 0) { // Annullato ... } else if (resultCode == 1) { // Confermato String opzioneSelezionata = data.getStringExtra("opzione_selezionata"); ... } } }

Nel codice allegato alla lezione trovate gli esempi SubActivityDemo02 e SubActivityDemo03 , che dimostrano luso di una sotto-attivit in grado di restituire risultati.

onBackPressed() Il metodo onBackPressed() della classe Activity pu essere ridefinito dallo sviluppatore per intercettare la pressione del tasto back del dispositivo durante lesercizio dellattivit. Per default il tasto back causa la chiusura dellActivity corrente ed il ritorno a quella precedente (o alle schermate di sistema). Tuttavia ogni applicazione ed ogni attivit sono libere di cambiare questo comportamento e decidere quale funzionalit assegnare al tasto back. Nel far ci, importante che il tasto risulti comunque coerente con la logica dellapplicazione ed intuitivo da utilizzare. Ad esempio nel browser di sistema il tasto back viene intercettato ed usato per fare indietro nella cronologia di navigazione delle pagine Web. Solo quando si arriva in fondo alla cronologia, e pertanto non ci sono pi pagine su cui retrocedere, allora unulteriore pressione del tasto back causa la chiusura dellattivit. Si tratta di un modello coerente, funzionale ed usabile. Per ridefinire il comportamento del tasto back non dovete far altro che inserire nella vostra Activity un metodo cos dichiarato:
@Override public void onBackPressed() { // Fa ci che vuoi }

Pagina 10

Anda mungkin juga menyukai