ANR (Application Not Responding) è una notifica di sistema Android che appare quando un'applicazione smette di rispondere all'input dell'utente per più di 5 secondi. Secondo Android Developers, la causa principale sono le operazioni lunghe sul thread principale che bloccano l'elaborazione dei tocchi e il rendering dell'interfaccia. Comprendere i meccanismi di ANR è essenziale per ogni sviluppatore Android per creare applicazioni reattive.
Punti chiave
ANR (Application Not Responding) è una finestra di dialogo del sistema operativo Android che appare quando un'applicazione smette di rispondere all'input dell'utente. Il sistema traccia il tempo di elaborazione degli eventi tramite InputDispatcher: se un tocco o una pressione di un pulsante non viene gestito entro 5 secondi, Android mostra una finestra che offre di chiudere o attendere l'applicazione.
Il meccanismo ANR protegge l'esperienza utente dalle applicazioni bloccate. Android non permette a un'applicazione di bloccare l'intero sistema — a differenza dei sistemi operativi desktop, la piattaforma mobile limita forzatamente il tempo di elaborazione degli eventi. BroadcastReceiver ha un limite di 10 secondi e un servizio in primo piano ha 20 secondi.
ANR NON è un'eccezione nel codice — è un meccanismo di sistema a livello di processi Linux. Android invia un segnale SIGQUIT al processo, dopo di che il sistema salva lo stack di chiamate di tutti i thread nel file traces.txt. Lo sviluppatore non riceve ANR come eccezione catch, ma come report dopo il riavvio dell'applicazione. Su Android 11+, l'API ApplicationExitInfo permette di ottenere programmaticamente la ragione della terminazione del processo, incluso ANR — questo semplifica la raccolta di statistiche senza analisi manuale di traces.txt.
Cinque categorie di operazioni portano costantemente ad ANR nelle applicazioni Android. Ognuna di esse blocca il thread principale, impedendo al sistema di elaborare gli eventi di input e il ridisegno dello schermo.
Le richieste HTTP sincrone eseguite sul thread UI sono la causa più comune di ANR tra gli sviluppatori principianti. Anche una richiesta veloce a un server può richiedere 1–3 secondi, e con una connessione scadente — 30 secondi o più. Android vieta esplicitamente le operazioni di rete sul thread principale a partire dall'API 11, lanciando NetworkOnMainThreadException.
Utilizza Coroutines o RxJava per chiamate asincrone. Le coroutine con il dispatcher Dispatchers.IO eseguono la richiesta in un thread di background e passano il risultato al thread principale tramite Dispatchers.Main. Questo elimina completamente il blocco del thread UI da parte delle operazioni di rete.
fun fetchUserData() {
CoroutineScope(Dispatchers.Main).launch {
val result = withContext(Dispatchers.IO) {
api.getUserData() // operazione in background
}
updateUI(result) // risultato sul thread principale
}
}
Elaborare grandi array di dati, analizzare JSON o XML, lavorare con bitmap direttamente sul thread principale — la seconda causa più frequente di ANR. Anche 300 millisecondi di lavoro continuo del thread UI senza tornare al ciclo di eventi causano un notevole ritardo nel rendering, e la soglia di 5 secondi viene registrata come ANR.
WorkManager e i servizi in background sono progettati per spostare i calcoli pesanti fuori dal thread principale. Utilizza AsyncTask (deprecato), ListenableFuture o Kotlin Flow per passare dati a blocchi senza bloccare la UI.
Un Deadlock si verifica quando due thread tengono blocchi e si aspettano a vicenda. Se uno dei thread è il thread principale, il sistema registra ANR esattamente dopo 5 secondi. Thread.join(), CountDownLatch.await() e blocchi synchronized chiamati dal thread UI comportano rischio di blocco.
Evita qualsiasi operazione bloccante sul thread principale. Invece di synchronized, usa ConcurrentHashMap; invece di Thread.join() — coroutine con async/await. Questa regola si applica a qualsiasi linguaggio in Android: Java, Kotlin o C++ tramite JNI.
BroadcastReceiver viene eseguito sul thread principale per impostazione predefinita. Se onReceive() è occupato per più di 10 secondi, Android mostra ANR. Caricare dati da un database o rete all'interno di onReceive è una strada garantita verso il blocco.
Utilizza goAsync() all'interno di BroadcastReceiver per passare a un thread di background, o registerReceiver con getBackgroundBroadcastReceiver(). Questo permette di gestire gli eventi senza bloccare la UI.
Query pesanti a ContentProvider o lavoro diretto con SQLite sul thread UI — una causa meno ovvia ma comune di ANR. Durante la migrazione del database o l'inserimento in massa di migliaia di record, il tempo di esecuzione può superare il limite di 5 secondi.
Sposta tutte le operazioni di database in thread di background usando Room con funzioni suspend. Room verifica automaticamente che la query non venga eseguita sul thread principale e lancia un'eccezione in caso di violazione.
Diagnosticare ANR differisce dal debugging delle eccezioni normali — non puoi catturare ANR in un blocco try-catch. La principale fonte di informazione è il file traces.txt, che Android crea al momento del blocco.
traces.txt contiene lo stack di chiamate di tutti i thread dell'applicazione al momento dell'ANR. Per leggere il file da un dispositivo reale, esegui il comando adb bugreport, che raccoglie un report completo di sistema includendo tutti gli ANR recenti. Per un emulatore, il file è disponibile in /data/anr/traces.txt. Lo stack di chiamate mostra quale metodo era in esecuzione sul thread principale al momento del blocco.
adb bugreport bugreport.zip
unzip -p bugreport.zip "*traces*" > traces.txt
Google Play Console fornisce la sezione ANR & Crash con report aggregati e frequenze di errore. Per ogni ANR, vengono mostrati lo stack di chiamate e le statistiche del dispositivo: modello, versione Android, regione. Questo permette di identificare ANR che dipendono da dispositivi o versioni di sistema specifici.
Android Studio dal 2021 include ANR Watchdog nel profiler. Registra automaticamente dump dei thread se il thread principale non risponde per più di un tempo soglia. Lo strumento mostra una timeline degli eventi: quali operazioni sono state avviate, quali metodi sono stati eseguiti e in quale fase si è verificato il blocco.
La prevenzione di ANR si basa su una regola fondamentale: il thread principale dovrebbe gestire solo eventi UI. Qualsiasi operazione più lunga di 16 millisecondi (tempo di un frame) dovrebbe essere eseguita in un thread di background.
StrictMode è uno strumento integrato Android per rilevare potenziali ANR durante lo sviluppo. Attivalo in Application.onCreate() con flag per operazioni su disco e rete. In caso di violazione, StrictMode lancia un'eccezione o scrive in logcat.
if (BuildConfig.DEBUG) {
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
.let { StrictMode.setThreadPolicy(it) }
}
Kotlin Coroutines — il modo standard di lavoro asincrono nelle applicazioni Android moderne. L'approccio principale: le operazioni di I/O vengono eseguite su Dispatchers.IO, il risultato viene passato a Dispatchers.Main per gli aggiornamenti UI. Per scenari simili a Flow, usa Dispatchers.Default per attività intensive di CPU.
RxJava rimane popolare nei progetti legacy. subscribeOn(Schedulers.io()) e observeOn(AndroidSchedulers.mainThread()) — il set minimo per prevenire ANR. La regola principale è la stessa: nessun Observable o Flowable dovrebbe emettere dati dal thread principale.
Firebase Crashlytics dalla versione SDK 18.4.0 supporta il monitoraggio ANR nativamente. Per Android 11+, Crashlytics utilizza l'API di sistema ApplicationExitInfo, che fornisce la ragione esatta della terminazione: ANR, Crash o kill di sistema. Attiva chiavi personalizzate con parametri di schermo e stato per analisi contestuale.
Cinque strumenti coprono tutte le fasi del lavoro con ANR: dal debugging su una workstation al monitoraggio in produzione. Ogni strumento risolve il proprio compito e fornisce dati per diversi scenari.
| Strumento | Scopo | Formato dati |
|---|---|---|
| StrictMode | Rilevamento durante lo sviluppo | Logcat / Exception |
| ANR Watchdog (Android Studio) | Tracciamento in tempo reale | Thread dump + timeline |
| Google Play Console | Statistiche aggregate | ANR rate + stack traces |
| Firebase Crashlytics | Monitoraggio in produzione | ApplicationExitInfo |
| adb bugreport | Report completo di sistema | traces.txt + logcat + dmesg |
Ogni strumento ha la propria nicchia: StrictMode cattura violazioni evidenti nelle fasi iniziali, Crashlytics mostra la frequenza reale di ANR tra gli utenti, e adb bugreport fornisce il quadro più completo per casi complessi. Combinali per una copertura totale.
Firebase Performance traccia il tempo di risposta del thread UI e crea automaticamente trace per operazioni sospettosamente lunghe. Se il thread principale si blocca per più di 500 ms, Performance registra una trace personalizzata con il nome del metodo colpevole. Questo permette di rilevare scenari ANR senza coinvolgimento dell'utente e prima che diventino critici.
L'integrazione con Firebase Crashlytics fornisce un quadro completo: Performance mostra i rallentamenti prima dell'ANR, e Crashlytics mostra il blocco stesso. Imposta avvisi in Firebase Console per un tasso ANR superiore allo 0.1% e riceverai notifiche sui nuovi problemi prima di reclami massivi degli utenti.
Domande frequenti
ANR è un blocco in cui l'applicazione non risponde ma rimane in memoria. Crash è una terminazione anomala completa con uscita dal processo. ANR può essere “sopravvissuto” se il sistema o l'utente aspettano una risposta, mentre Crash termina sempre l'applicazione.
No. ANR non è un'eccezione Java/Kotlin, ma un segnale di sistema a livello di processi (SIGQUIT). Uno sviluppatore non può gestirlo nel codice dell'applicazione. L'unico modo per rispondere ad ANR è analizzare i report dopo il riavvio.
Le prestazioni del dispositivo, la versione Android, il carico della CPU e il numero di processi in background influenzano la probabilità di ANR. Su dispositivi deboli, la stessa operazione può richiedere da 2 a 3 volte più tempo, superando il limite di 5 secondi.
10 secondi per un BroadcastReceiver normale in onReceive(). Per i servizi in primo piano, il limite è di 20 secondi, e per ContentProvider — non c'è un limite esplicito, ma bloccare il thread principale per più di 5 secondi causa comunque ANR.
Attiva StrictMode in tutte le build di debug, aggiungi monitoraggio tramite Firebase Crashlytics e usa adb bugreport quando ANR si verifica. ANR irregolari sono spesso correlati a condizioni di competizione o stati di rete specifici.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche