Mantieni reattiva la tua app

Figura 1. Una finestra di dialogo ANR mostrata all'utente.

Questo documento descrive come il sistema Android determina se un'app non risponde e mostra come mantenere reattiva la tua app.

Indipendentemente da quanto sia scritto bene il tuo codice, l'app potrebbe risultare ancora lenta, bloccarsi, bloccarsi per periodi significativi o richiedere troppo tempo per elaborare l'input. Se la tua app è in primo piano e non risponde, l'utente visualizza una finestra di dialogo L'applicazione non risponde (ANR), come mostrato nella figura 1. La finestra di dialogo ANR consente all'utente di forzare l'uscita dall'app. Se l'app non è in primo piano, significa che viene interrotta in modalità silenziosa. È fondamentale progettare la reattività nella tua app per ridurre al minimo le finestre di dialogo ANR.

Trigger ANR

In genere, il sistema visualizza un errore ANR se un'app non può rispondere all'input utente nel thread principale (noto anche come thread UI), impedendo al sistema di elaborare gli eventi di input utente in entrata.

Ad esempio, può verificarsi un errore ANR se un'app esegue un'operazione di I/O di blocco, come l'accesso alla rete, nel thread dell'interfaccia utente. Un altro esempio è quando un'app dedica troppo tempo alla creazione di una struttura in memoria elaborata o al calcolo della prossima mossa di un gioco nel thread dell'interfaccia utente.

In Android, la reattività delle app è monitorata dai servizi di sistema ActivityManager e WindowManager. Android mostra la finestra di dialogo ANR per un'app quando rileva una delle seguenti condizioni:

  • Nessuna risposta a un evento di input, ad esempio eventi di pressione di un tasto o tocco dello schermo, entro 5 secondi.
  • L'esecuzione di un elemento BroadcastReceiver non termina entro 10-20 secondi per intent in primo piano. Per ulteriori informazioni, consulta Timeout ricevitore trasmissione.

Evita ANR

Di seguito sono riportati suggerimenti generali per evitare gli errori ANR. Per maggiori dettagli sulla diagnosi e sul debug di diversi tipi di ANR, consulta le altre pagine di questa sezione.

  • Mantieni sempre sbloccato il thread principale e utilizza i thread in modo strategico.

    • Non eseguire operazioni di blocco o a lunga esecuzione sul thread principale dell'app. Crea invece un thread di lavoro dove svolgi la maggior parte del lavoro.

    • Prova a ridurre al minimo qualsiasi contesa dei blocchi tra il thread principale e altri thread.

    • Riduci al minimo il lavoro non correlato all'UI sul thread principale, ad esempio durante la gestione delle trasmissioni o dei servizi in esecuzione. Qualsiasi metodo eseguito nel thread dell'interfaccia utente deve fare il meno lavoro possibile su quel thread. In particolare, la configurazione delle attività deve essere il meno possibile in metodi chiave del ciclo di vita, come onCreate() e onResume(). Consulta la panoramica del lavoro in background per ulteriori informazioni sulle soluzioni disponibili per pianificare il lavoro su un thread in background e comunicare con l'interfaccia utente.

    • Fai attenzione quando condividi pool di thread tra i componenti. Non utilizzare gli stessi thread per operazioni potenzialmente lunghe che bloccano operazioni e attività sensibili al tempo, come la ricezione di trasmissioni.

  • Mantieni rapido l'avvio dell'app. Riduci al minimo le operazioni lente o di blocco nel codice di avvio dell'app, ad esempio i metodi eseguiti durante l'inizializzazione del dagger.

  • Se utilizzi BroadcastReceiver, valuta la possibilità di eseguire ricevitori di trasmissioni in un thread non principale utilizzando Context.registerReceiver. Per ulteriori informazioni, consulta la pagina ANR in BroadcastRicevir.

ANR in BroadcastRicevir

I tempi di esecuzione di BroadcastReceiver sono limitati perché i ricevitori di trasmissione sono concepiti per svolgere piccole quantità di lavoro discrete in background, come il salvataggio di un'impostazione o la registrazione di un Notification. Pertanto, come con altri metodi chiamati nel thread dell'interfaccia utente, le app devono evitare operazioni o calcoli potenzialmente a lunga esecuzione in un ricevitore broadcast. Invece di eseguire attività a lunga esecuzione tramite il thread dell'interfaccia utente, eseguile in background per un'esecuzione successiva. Vedi Panoramica del lavoro in background per ulteriori informazioni sulle possibili soluzioni.

Un altro problema comune con gli oggetti BroadcastReceiver si verifica quando vengono eseguiti troppo spesso. Un'esecuzione frequente in background può ridurre la quantità di memoria disponibile per altre app. Per ulteriori informazioni su come abilitare e disabilitare gli oggetti BroadcastReceiver in modo efficiente, consulta Panoramica dei trasmissioni.

Aumenta la reattività

In genere, da 100 a 200 ms è la soglia oltre la quale gli utenti percepiscono la lentezza di un'app. Di seguito sono riportati ulteriori suggerimenti per rendere la tua app reattiva per gli utenti:

  • Se la tua app esegue operazioni in background in risposta all'input utente, mostra che è in corso l'avanzamento, ad esempio con ProgressBar nella UI.

  • Per i giochi in particolare, esegui calcoli per le mosse in un thread di lavoro.

  • Se la fase di configurazione iniziale dell'app richiede molto tempo, potresti mostrare una schermata iniziale o eseguire il rendering della visualizzazione principale il più rapidamente possibile. Indica che il caricamento è in corso e inserisci le informazioni in modo asincrono. In entrambi i casi, consigliamo di indicare in qualche modo l'avanzamento, in modo che l'utente non percepisca che l'app è bloccata.

  • Utilizza strumenti per le prestazioni come Perfetto e CPU Profiler per determinare i colli di bottiglia nella reattività della tua app.