T#003 – Usiamo Activity e Intent nelle nostre applicazioni Android.

Ciao a tutti, eccoci al terzo appuntamento con i nostri tutorial di programmazione Android.
Dopo aver visto come configurare Eclipse e l’sdk di Android creiamo la nostra prima applicazione con qualche funzionalità più interessante. In questo tutorial vedremo in dettaglio i concetti di Activity e Intent arrivando a scrivere un piccolo esempio pratico comprendente due Activity collegate fra loro, che ci permetteranno di mostrare a video un elenco di url, di aprire i rispettivi indirizzi in un browser nella nostra applicazione Android o ancora di condividere uno di questi link attraverso i principali Social Network.

Activity

Un’activity è sicuramente il componente di una applicazione Android più utilizzato, rappresenta una schermata con cui l’utente può interagire. Solitamente una applicazione è composta da più Activity richiamabili fra loro. Tecnicamente una Activity è una classe java che estende (anche indirettamente) la classe android.app.Activity. Possiamo creare una Activity vuota scrivendo una classe java come questa:

1
2
3
4
5
6
7
8
package it.devapp;
 
import android.app.Activity;
 
public class MainActivity extends Activity
{
 
}

Per essere utilizzabile deve essere definita nel manifest dell’applicazione:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="it.devapp" android:versionCode="1" android:versionName="1.0">
 
    <application android:icon="@drawable/icon" 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>
    </application>
</manifest>

In questo modo abbiamo definito la nostra Activity e abbiamo detto al sistema operativo di lanciarla quando viene eseguito un intent MAIN con categoria LAUNCHER. Vedremo in seguito cosa è un intent, per adesso ci basta sapere che definendola in questo modo l’Activity MainActivity è quella lanciata quando si avvia l’applicazione. Infatti avviando l’applicazione sull’emulatore o su un device collegato viene lanciata l’Activity appena definita, non avendo ancora scritto nessun metodo all’interno della classe viene mostrato una semplice schermata nera contenente nella parte alta la label dell’Activity definita nel manifest.

Ciclo di vita

Android è un sistema operativo multitasking, in ogni momento ci possono essere più applicazioni in esecuzione contemporaneamente. Data la dimensione ridotta del display c’è comunque una sola applicazione visibile mentre le altre sono in background, con una pressione lunga del tasto home è possibile vedere tutte le applicazioni eseguite di recente.

Ogni applicazione aperta mantiene uno stack delle Activity visualizzate dall’utente per poter gestire il tasto fisico back (il comportamento è lo stesso del tasto “back” di un brower). Mantenendo uno stack quando viene premuto il tasto back il sistema non fa altro che rimuovere l’Activity corrente dall’ultima posizione dello stack e “risvegliare” l’Activity che era alla penultima posizione.
Quando si passa da una applicazione all’altra viene mostrata l’utima activity aperta se l’applicazione è già stata usata o quella predefinita in tutti gli altri casi.

Da questa descrizione si capisce che una Activity può essere in più stati e che può esistere anche se non è direttamente visibile. Per gestire i cambiamenti di stato è possibile riscrivere alcuni metodi che vengono richiamati dal sistema operativo in determinate situazioni. Un diagramma che espone tutti i possibili cambi di stato è il seguente:


Ciclo di vita

Dopo la chiamata a onStart, e fino a che non viene invocato onStop, l’Activity è visibile (anche solo parzialmente nel caso in cui l’Activity che la copre non sia a tutto schermo). Dopo la chiamata a onResume e fino alla chiamata di onPause l’Activity è quella mostrata in foreground con cui l’utente può interagire. A prima vista può sembrare molto complicato ma solitamente non è necessario riscrivere tutti questi metodi.

I metodi utilizzati più di frequente sono 3:

  • onCreate: richiamato alla partenza dell’Activity, di solito contiene il codice che inizializza il layout grafico;
  • onResume: richiamato sia quando l’Activity viene mostrata la prima volta (dopo onCreate) che quando torna visibile dopo che è stata messa in background. E’ il posto giusto in cui mettere la logica che popola i dati visualizzati nel layout definito nel metodo onCreate
  • onDestroy: richiamato prima che l’Activity venga terminata, deve essere riscritto se serve fare pulizia su risorse create alla partenza dell’Activity

Un caso particolare è rappresentato dal cambio di orientation (l’utente passa da portrait a landscape o viceversa). In questo caso l’Activity visualizzata viene distrutta e ricreata completamente. Nel caso in cui si voglia salvare dei dati prima che l’Activity venga distrutta è possibile sovrascrivere il metodo onSaveInstanceState. Questo metodo ha un parametro di tipo Bundle che contiene dei metodi put (per esempio putInt e putString) che permettono di memorizzare dei dati.
Lo stesso bundle viene ripassato al metodo onCreate in modo che sia possabile ricreare l’interfaccia correttamente.

Intent

Un Intent è definitio nella javadoc della classe android.content.Intent come una “descrizione astratta di un’operazione da eseguire”. In pratica indica l’intenzione di voler effettuare un’azione su un dispositivo Android; l’azione da eseguire spesso coincide con il lancio di una Activity ma può essere anche legata a un Service o a un BroadcastReceiver.

Un Intent può essere di due tipi:

  • esplicito: quando creiamo l’Intent dobbiamo specificare la classe da eseguire;
  • implicito: specifichiamo l’azione da eseguire senza sapere chi sarà il destinatario.
    Questo tipo di Intent è alla base di Android e permette di scrivere applicazioni che interagiscono fra di loro senza conoscersi. Un esempio è costituito dalle varie applicazioni che gestiscono gli sms, tutte rispondono all’Intent per mandare gli sms. Quando una qualunque applicazione vuole mandare un sms lancerà un Intent di scrittura sms senza sapere quale applicazione sarà effettivamente eseguita.

Un piccolo esempio pratico

Vediamo adesso un semplice esempio composto da due Activity, la prima mostra una lista di indirizzi web.

Il modo più semplice per creare una Activity contenente una lista è creare una classe che estende ListActivity. Il popolamento dei dati nella lista avviene impostando il listAdaper in cui specifichiamo il layout da usare (in questo caso un layout standard) e i dati da mostrare; parleremo più in dettaglio di liste e listAdapter in un altro tutorial.

Il codice per questa Activity è riportato di seguito:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MainActivity extends ListActivity
{
	@Override
	protected void onResume()
	{
		super.onResume();
		setListAdapter(new ArrayAdapter<String>(this, 
			android.R.layout.simple_list_item_1, android.R.id.text1, 
			new String[] { 
				"http://www.google.it", 
				"http://developer.android.com", 
				"http://www.devapp.it" 
			}
		));
	}
}

Lanciando l’Activity viene mostrata una lista di tre indirizzi web:



Aggiungiamo un evento sul click di un elemento della lista che apre un’Activity di dettaglio che mostra la pagina web corrispondente all’indirizzo mostrato. Il click su un elemento viene intercettato riscrivendo il metodo onListItemClick di ListActivity. Per richiamare l’Activity di dettaglio creiamo un Intent esplicito in cui specifichiamo la classe corrispondente all’Activity da mostrare e un parametro associato alla chiave “url” in cui passiamo l’indirizzo da mostrare:

1
2
3
4
5
6
protected void onListItemClick(ListView l, View v, int position, long id)
{
	Intent intent = new Intent(this, WebViewActivity.class);
	intent.putExtra("url", (String) getListAdapter().getItem(position));
	startActivity(intent);
}

L’Activity di dettaglio contiene una WebView (in pratica un browser embedded nella nostra interfaccia) in cui viene caricata la pagina corrispondente all’url passato:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class WebViewActivity extends Activity
{
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		WebView webview = new WebView(this);
		setContentView(webview);
 
		String url = getIntent().getStringExtra("url");
		setTitle(url);
		webview.loadUrl(url);
	}
}

Vediamo adesso un esempio di Intent implicito, sul long click di un elemento della lista aggiungiamo la possibilità di condividere un link. Nel metodo onCreate dell’Activity aggiungiamo un listener sull’evento onItemLongClick della lista:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected void onCreate(Bundle savedInstanceState)
{
	super.onCreate(savedInstanceState);
	getListView().setOnItemLongClickListener(new OnItemLongClickListener()
	{
		@Override
		public boolean onItemLongClick(AdapterView<?> adapterView, 
			View view, int pos, long id)
		{
			final Intent intent = new Intent(Intent.ACTION_SEND);
			intent.setType("text/plain");
			intent.putExtra(Intent.EXTRA_TEXT, 
				(String) adapterView.getItemAtPosition(pos));
			startActivity(Intent.createChooser(intent, 
				getString(R.string.share_message)));
			return true;
		}
	});
}

Nell’Intent che creiamo non specifichiamo la classe da invocare ma solamente la action da chiamare ACTION_SEND, il tipo text/plain e un testo da condividere.

Usando il metodo Intent.createChooser viene mostrato sempre un dialog in cui scegliere quale applicazione usare per effettuare la condivisione senza la possibilità di impostare un’applicazione come predefinita. Il dialog mostra tutte le Activity delle applicazioni installate che sono registrate per ascoltare l’Intent che lanciamo:



Sorgenti del progetto

Se avete problemi con il nostro tutorial potete scaricare sul vostro pc i sorgenti del progetto mostrato seguendo questo indirizzo.

By Fabio Collini

Da agosto 2009 sono un freelance android developer, ho rilasciato due applicazioni nell'Android Market: Apps Organizer e Folder Organizer. Presso OmniaGroup ricopro il ruolo di Tech Leader nell'ambito di un progetto di rich internet application che utilizza JSF, JPA(EclipseLink) ed EJB3.

31 comments

  1. ok… dopo questa guida, ho capito che non sapendo nulla di programmazione, non posso programmare per android… peccato, ci avevo sperato…

  2. Ciao,
    volevo sapere se è possibile e come farlo, avendo settati diversi PendingIntent di un’alarmManager, avere la lista degli intent pendenti per aggiornarli o modificarli.

    Grazie.

  3. Non riesco a compilare l’intent implicito in quanto R.string.share_message
    mi ritorna un errore di compilazione.
    In pasrticolare il “.share_message” sembra essere il problema.

    Il messaggio del compilatore è il seguente:
    share_message cannot be resolved or is not a field.
    Mi puoi aiutare?
    grazie.

    1. Ciao, R.string è generata automaticamente da Android in base al file res/strings.xml.
      Nel tuo caso ti manca una riga in questo file con share_message come chiave.
      Se scarichi i sorgenti del progetto puoi vedere la versione funzionante del file

  4. ho seguito attentamente la guida, il compilatore non mi da nessun errore ma se provo a far partire l’applicazione mi da errore, sia su emulatore, sia su telefono. Ogni volta da errore da interruzione improvvisa. Cosa può essere?
    Grazie

    1. Ciao, prova a guardare nel logcat quale è l’errore. Logcat è una view di eclipse, per vederlo scegli da dentro Eclipse Window -> Show view -> Logcat.
      Da lì dovresti vedere l’eccezione vera e capire il punto del codice in cui ti dà errore.
      Ciao, Fabio

  5. Ciao, ottima guida, il codice funziona benissimo ma sul longclick invece che venir fuori il list degli share possibili viene fuori il form di invio mail.

    Qualche idea? grazie 🙂

    1. Ciao, dove stai provando il codice? Probabilmente la lista conterrebbe solamente la mail e quindi ti viene aperto direttamente quello.


  6. Marco:

    Ciao, ottima guida, il codice funziona benissimo ma sul longclick invece che venir fuori il list degli share possibili viene fuori il form di invio mail.
    Qualche idea? grazie

    Anche a me succede questo.
    Sto testando il tutto su simulatore che comunque dovrebbe avere installate delle applicazioni di default…

  7. Ciao Fabio ho perso il conto delle domande fatte ma questa e davvero importante : se io ho in una gridview degli elementi posso mettere la tua stessa opzione di condivisione oppure vale solo per le listview ? se si dove nella classe con dentro la gridview o nell ImageAdapter della gridview ?

    1. Ciao, non cambia niente rispetto a usare una ListView! Anche la classe GridView ha il metodo setOnItemLongClickListener che è stato usato in questo esempio.

  8. Ciao a tutti,
    dopo varie peripezie sono riuscita a fare girare l’applicazione…Problema: sembra che il metodo Intent.createChooser con me non funziona, infatti seleziono il link e semplicemente mi si apre un’altra schermata con scritto che la pagina web non è disponibile. il codice è uguale, non so proprio dove andare a mettere le mani 🙁

    Grazie

  9. Ciao Mary,
    confronta il tuo file AndroidManifest.xml con quello che scarichi dal sito. Probabilmente ti manca questa riga:

    Praticamente se la tua applicazione ha bisogno dell’accesso ad internet devi impostare i permessi sul file di Manifest. Senza questa impostazione Android non ti da i permessi per accedere ad internet.
    Ciao

    Ciao

  10. Non mi compare la stringa…Ultima prova.
    Riprovo senza mettere i minori/maggiori:
    uses-permission android:name=”android.permission.INTERNET
    Se non compare spero che sistemino gli addetti.
    Saluti

    1. Confrontando il Manifest con quello scaricato si nota che, arrivati a questo punto, manca anche la chiamata alla WebViewActivity. Aggiungendola dovrebbe funzionare tutto.
      activity android:name=”.WebViewActivity”/

      N.B. aggiungere gli apici di apertura e chiusura (minore/maggiore) a cio’ che c’e’ scritto sopra.


  11. Fabio Collini:

    Ciao, prova a guardare nel logcat quale è l’errore. Logcat è una view di eclipse, per vederlo scegli da dentro Eclipse Window -> Show view -> Logcat.
    Da lì dovresti vedere l’eccezione vera e capire il punto del codice in cui ti dà errore.
    Ciao, Fabio

    ho lo stesso problema di simone #6 nel mio caso il logcat rimane completamente pulito :/

    1. Ciao, probabilmente è perchè non hai il device selezionato. Nella vista device di eclipse (se non la vedi clicca su windows -> show view -> device) seleziona il device su cui stai eseguendo il codice

  12. Scusate… a me da errore quando scrivo extends ListActivity… e non capisco perchè

  13. Ciao, perchè a me da errore quando scrivo

    public class MainActivity extends ListActivity

    ?

  14. alla domanda di Enrico rispondo io: non trova le classi. Ho risolto aggiungendo “android.app.” a ListActivity, il problema è che dopo dà un altro errore, e cioè non trova “ArrayAdapter”. Come si fa a dare una o più librerie di classi che trovi automaticamente? E perché ad alcuni funziona a me (e a Enrico) no?

  15. cercando nelle classi di Android ho trovato che la classe ArrayAdapter sta nel package android.widget, quindi devi aggiungere anche questa riga (sotto il primo import):
    import android.widget.ArrayAdapter;
    ciao

  16. Ciao, per non impazzire con gli import vi consiglio di usare il comando “Organize imports” di Eclipse, è dentro il menu source. In pratica fa tutto da solo cercando e aggiungendo gli import giusti.
    Ciao, Fabio

  17. questa è una grande dritta. Ma sembra che il tutorial dia per scontato che in fase di compilazione la classe venga trovata. E’ per convenzione o da qualche altra parte c’è un altro “import” o un altro comando simile?

  18. Ciao ho un problema….avviando l’applicazione mi spuntano i tre siti,ma quando ci clicco in uno dei tre l’emulatore mi da errore xke??

    1. Ciao Marco,

      Io avevo lo stesso problema, poi circa a metà dei posto ho trovato la soluzione, mi mancavano due righe nel file Manifest, se scarichi lo zip a fine articolo puoi confrontare i file e vedere se è quello il problema!

  19. A me da un errore in compilazione, mi dice Array adapter cannot be resolved be a type, come posso risolvere?

  20. In primis grazie per il tutoria…Volevo chiederti una cosa:
    Tramite questo codice noi possiamo postare un link/testo su facebook, mA quando viene postato appare la scritta “tramite cellulare”
    Cosa si può fare per vedere il post su facebook con sotto scritto “Tramite ‘La mia applicazione’ “?

  21. salve, volevo chiedere come cambiare l’immagine dell’anteprima del link che condivido su facebook.

Comments are closed.