La classe Activity è un componente fondamentale di un'app per Android e il modo in cui le attività vengono avviate e assemblate è una parte fondamentale del modello di applicazione della piattaforma. A differenza dei paradigmi di programmazione in cui le app vengono avviate con un metodo main, il sistema Android avvia il codice in un'istanza Activity richiamando metodi di callback specifici che corrispondono a fasi specifiche del suo ciclo di vita.
Questo documento introduce il concetto di attività e fornisce alcune indicazioni di base su come utilizzarle. Per ulteriori informazioni sulle best practice per la progettazione dell'architettura della tua app, consulta la Guida all'architettura delle app.
Il concetto di attività
L'esperienza con l'app mobile differisce da quella con la versione desktop in quanto l'interazione dell'utente con l'app non inizia sempre nello stesso punto. Il percorso dell'utente spesso inizia in modo non deterministico. Ad esempio, se apri un'app email dalla schermata Home, potresti visualizzare un elenco di email. Al contrario, se utilizzi un'app di social media che avvia l'app email, potresti andare direttamente alla schermata dell'app email per scrivere un'email.
La classe Activity è progettata per facilitare questo paradigma. Quando un'app
richiama un'altra app, l'app chiamante richiama un'attività nell'altra app, anziché
l'app come un tutto atomico. In questo modo, l'attività funge da punto di
ingresso per l'interazione di un'app con l'utente. Implementi un'attività come sottoclasse della classe Activity.
Un'attività fornisce la finestra in cui l'app disegna la sua UI. Questa finestra in genere riempie lo schermo, ma potrebbe essere più piccola dello schermo e fluttuare sopra le altre finestre.
In genere, un'attività in un'app viene specificata come attività principale, ovvero la prima schermata che viene visualizzata quando l'utente avvia l'app. Nelle app Compose moderne, questa è l'unica attività necessaria, in quanto ospita i composable in un'architettura a singola attività anziché possedere una gerarchia di oggetti View. Invece di avere più attività per le schermate, i composable nell'host dell'attività hanno più destinazioni di navigazione.
Per utilizzare le attività nella tua app, devi registrarne le informazioni nel manifest dell'app ed è buona norma conoscere i cicli di vita delle attività. Il resto di questo documento introduce questi argomenti.
Configurare il manifest
Affinché la tua app possa utilizzare le attività, devi dichiararle e alcuni dei loro attributi nel manifest.
Dichiarare le attività
Per dichiarare la tua attività, apri il file manifest e aggiungi un elemento <activity>
come elemento secondario dell'elemento <application>. Ad esempio:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
L'unico attributo obbligatorio per questo elemento è android:name, che
specifica il nome della classe dell'attività. Puoi anche aggiungere attributi che
definiscono le caratteristiche dell'attività, come etichetta, icona o tema dell'interfaccia utente. Per ulteriori
informazioni su questi e altri attributi, consulta la documentazione di riferimento dell'elemento <activity>.
Dichiarare i filtri per intent
I filtri per intent sono una funzionalità molto potente della piattaforma Android. Consentono di avviare un'attività non solo in base a una richiesta esplicita, ma anche a una implicita. Ad esempio, una richiesta esplicita potrebbe indicare al sistema di "Avviare l'attività Invia email nell'app Gmail". Al contrario, una richiesta implicita indica al sistema di "Avviare una schermata Invia email in qualsiasi attività che possa svolgere il lavoro". Quando la UI di sistema chiede a un utente quale app utilizzare per eseguire un'attività, è in funzione un filtro per intent.
Puoi sfruttare questa funzionalità dichiarando un attributo <intent-filter>
nell'elemento <activity>. La definizione di questo elemento
include un elemento <action> e, facoltativamente, un elemento <category>
e/o un elemento <data>. Questi elementi si combinano per specificare il
tipo di intent a cui può rispondere la tua attività. Ad esempio, il seguente
snippet di codice mostra come configurare un'attività che invia dati di testo ed email
e riceve richieste da altre attività per farlo:
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="mailto" />
</intent-filter>
</activity>
In questo esempio, l'elemento <action> specifica che questa attività invia
dati. La dichiarazione dell'elemento <category> come DEFAULT consente all'attività
di ricevere richieste di avvio. L'elemento <data> specifica il tipo di
dati che questa attività può inviare. Il seguente snippet di codice mostra come chiamare
l'attività descritta sopra per comporre un'email:
fun composeEmail(addresses: Array<String>, subject: String) {
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:") // Only email apps handle this.
putExtra(Intent.EXTRA_EMAIL, addresses)
putExtra(Intent.EXTRA_SUBJECT, subject)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
Se vuoi che la tua app sia autonoma e non consenta ad altre app di attivare le sue attività, non hai bisogno di altri filtri per intent. Le attività che non vuoi rendere disponibili ad altre applicazioni non devono avere filtri per intent e puoi avviarle tu stesso utilizzando intent espliciti. Per ulteriori informazioni su come le tue attività possono rispondere agli intent, vedi Intent e filtri per intent.
Gestire gli intent in entrata
L'esempio seguente mostra un pattern per la gestione del ciclo di vita dell'attività durante la gestione di più tipi di intent: condivisioni di testo singolo, singole immagini e più array di immagini. Instradando questi input diversi tramite una funzione handleIntent centralizzata, si garantisce che le azioni ACTION_SEND e ACTION_SEND_MULTIPLE vengano analizzate e delegate correttamente al ViewModel per un aggiornamento reattivo della UI.
class ExampleActivity : ComponentActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIntent(intent)
setContent {
ComposeApp(viewModel)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
when (intent?.action) {
Intent.ACTION_SEND -> {
if ("text/plain" == intent.type) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
viewModel.handleText(it) // Update UI to reflect text being shared
}
} else if (intent.type?.startsWith("image/") == true) {
(intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))?.let {
viewModel.handleImage(it) // Update UI to reflect image being shared
}
}
}
Intent.ACTION_SEND_MULTIPLE -> {
if (intent.type?.startsWith("image/") == true) {
intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
viewModel.handleMultipleImages(it) // Update UI to reflect multiple images being shared
}
} else {
// Handle other types
}
}
else -> {
// Handle other intents
}
}
}
}
Dichiarare le autorizzazioni
Puoi utilizzare il tag <activity> del manifest per controllare quali app possono avviare
una determinata attività. Un'attività principale non può avviare un'attività secondaria a meno che
entrambe le attività non abbiano le stesse autorizzazioni nel manifest. Se dichiari un elemento
<uses-permission> per un'attività principale, ogni attività secondaria
deve avere un elemento <uses-permission> corrispondente.
Ad esempio, se la tua app vuole utilizzare un'app ipotetica denominata SocialApp per condividere un post sui social media, SocialApp stessa deve definire l'autorizzazione che un'app che la chiama deve avere:
<manifest>
<activity android:name="...."
android:permission="com.google.socialapp.permission.SHARE_POST"
/>
Per poter chiamare SocialApp, la tua app deve corrispondere al set di autorizzazioni nel manifest di SocialApp:
<manifest>
<uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
</manifest>
Per ulteriori informazioni su autorizzazioni e sicurezza in generale, consulta l'elenco di controllo della sicurezza.
Gestione del ciclo di vita dell'attività
Nel corso della sua durata, un'attività passa attraverso una serie di stati. Utilizzi una serie di callback per gestire le transizioni tra gli stati. Le sezioni che seguono introducono queste richiamate. In un'app Compose, non è consigliabile collegarsi direttamente a questi callback. Utilizza invece l'API Lifecycle per osservare le modifiche dello stato. Per maggiori informazioni, consulta la sezione Integrare il ciclo di vita con Compose.
onCreate
Devi implementare questo callback, che viene attivato quando il sistema crea la tua attività. L'implementazione deve inizializzare i componenti essenziali dell'attività: ad esempio, l'app deve creare visualizzazioni e associare i dati alle liste qui.
In un'app Compose, utilizza questo callback per configurare il componibile host utilizzando
setContent, come mostrato di seguito:
class MyActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text(text = stringResource(id = R.string.greeting))
}
}
}
Al termine di onCreate, il successivo callback è sempre onStart.
onStart
Quando onCreate esce, l'attività entra nello stato Avviata e diventa visibile all'utente. Questo callback contiene l'equivalente dei
preparativi finali dell'attività per passare in primo piano e diventare
interattiva.
onResume
Il sistema richiama questo callback appena prima che l'attività inizi a interagire
con l'utente. A questo punto, l'attività si trova in cima allo stack delle attività
e acquisisce tutti gli input utente. La maggior parte delle funzionalità di base di un'app viene implementata
nel metodo onResume.
Il callback onPause segue sempre onResume.
onPause
Il sistema chiama onPause quando l'attività perde lo stato attivo ed entra in uno stato
di pausa. Questo stato si verifica, ad esempio, quando l'utente tocca il pulsante Indietro o
Recenti. Quando il sistema chiama onPause per la tua attività, significa tecnicamente che la tua attività è ancora parzialmente visibile, ma il più delle volte è un'indicazione che l'utente sta abbandonando l'attività e che questa entrerà presto nello stato Interrotto o Ripreso.
Un'attività nello stato In pausa potrebbe continuare ad aggiornare la UI se l'utente si aspetta che la UI venga aggiornata. Esempi di attività di questo tipo includono una schermata di una mappa di navigazione o un media player in riproduzione. Anche se queste attività perdono lo stato attivo, l'utente si aspetta che la UI continui ad aggiornarsi.
Non devi utilizzare onPause per salvare dati di applicazioni o utenti, effettuare
chiamate di rete o eseguire transazioni di database. Per informazioni sul salvataggio
dei dati, vedi Salvataggio e ripristino dello stato dell'interfaccia utente temporanea.
Una volta terminata l'esecuzione di onPause, il callback successivo è onStop o onResume, a seconda di cosa succede dopo che l'attività entra nello stato Paused.
onStop
Il sistema chiama onStop quando l'attività non è più visibile all'utente. Ciò può accadere perché l'attività viene eliminata, ne viene avviata una nuova o una esistente entra nello stato di ripresa e copre l'attività interrotta. In tutti questi casi, l'attività interrotta non è più
visibile.
Il callback successivo chiamato dal sistema è onRestart, se l'attività torna a interagire con l'utente, o onDestroy se l'attività termina completamente.
onRestart
Il sistema richiama questo callback quando un'attività nello stato Interrotto sta per riavviarsi. onRestart ripristina lo stato dell'attività dal momento
in cui è stata interrotta.
Questo callback è sempre seguito da onStart.
onDestroy
Il sistema richiama questo callback prima che un'attività venga eliminata.
Questo callback è l'ultimo che l'attività riceve. onDestroy viene
di solito implementato per garantire che tutte le risorse di un'attività vengano rilasciate
quando l'attività o il processo che la contiene viene eliminato.
Questa sezione fornisce solo un'introduzione all'argomento. Per un trattamento più dettagliato del ciclo di vita dell'attività e dei relativi callback, consulta Il ciclo di vita dell'attività.