ANR

Quando il thread dell'interfaccia utente di un'app per Android viene bloccato per troppo tempo, viene attivato un errore "L'applicazione non risponde" (ANR). Se l'app è in primo piano, il sistema mostra all'utente una finestra di dialogo, come illustrato nella figura 1. La finestra di dialogo ANR offre all'utente la possibilità di forzare l'uscita dall'app.

Finestra di dialogo ANR visualizzata all'utente.
Figura 1. Finestra di dialogo ANR visualizzata dall'utente

Gli errori ANR sono un problema perché il thread principale dell'app, responsabile dell'aggiornamento dell'interfaccia utente, non riesce a elaborare gli eventi di input dell'utente o a disegnare, causando frustrazione all'utente. Per saperne di più sul thread principale dell'app, consulta la panoramica di processi e thread.

Un errore ANR viene attivato per la tua app quando si verifica una delle seguenti condizioni:

  • Timeout dell'invio dell'input: se la tua app non ha risposto a un evento di input (ad esempio la pressione di un tasto o il tocco dello schermo) entro 5 secondi.
  • Servizio in esecuzione:se un servizio dichiarato dalla tua app non riesce a terminare l'esecuzione di Service.onCreate e Service.onStartCommand/Service.onBind entro pochi secondi.
  • Service.startForeground non chiamato: se la tua app utilizza Context.startForegroundService per avviare un nuovo servizio in primo piano ma il servizio non chiama startForeground entro 5 secondi.
  • Trasmissione di intent:se un BroadcastReceiver non ha terminato l'esecuzione entro un determinato periodo di tempo. Se l'app ha attività in primo piano, questo timeout è di 5 secondi.
  • Interazioni JobScheduler:se un JobService non viene restituito da JobService.onStartJob o JobService.onStopJob entro pochi secondi, o se viene avviato un job avviato dall'utente e la tua app non chiama JobService.setNotification entro pochi secondi dopo la chiamata di JobService.onStartJob. Per le app che hanno come target Android 13 e versioni precedenti, gli errori ANR sono silenziosi e non vengono segnalati all'app. Per le app che hanno come target Android 14 e versioni successive, gli errori ANR sono espliciti e vengono segnalati all'app.

Se la tua app presenta errori ANR, puoi utilizzare le indicazioni riportate in questo documento per diagnosticare e risolvere il problema.

Diagnosticare gli errori ANR

Esistono alcuni pattern comuni da cercare durante la diagnosi degli errori ANR:

  • L'app esegue operazioni lente che coinvolgono I/O sul thread principale.
  • L'app sta eseguendo un calcolo lungo sul thread principale.
  • Il thread principale sta eseguendo una chiamata Binder sincrona a un altro processo e quest'altro processo impiega molto tempo per restituire una risposta.
  • Il thread principale è bloccato in attesa di un blocco sincronizzato per un'operazione lunga che si sta svolgendo su un altro thread.
  • Il thread principale è in un deadlock con un altro thread, nel tuo processo o tramite una chiamata binder. Il thread principale non sta solo aspettando il completamento di un'operazione lunga, ma si trova in una situazione di stallo.

Le seguenti tecniche possono aiutarti a determinare la causa degli errori ANR.

HealthStats

HealthStats fornisce metriche sull'integrità di un'applicazione acquisendo il tempo totale di utente e sistema, il tempo della CPU, le statistiche di rete e radio, il tempo di accensione/spegnimento dello schermo e le sveglie. In questo modo puoi misurare l'utilizzo complessivo della CPU e il consumo della batteria.

Debug

Debug ti aiuta a ispezionare le applicazioni Android durante lo sviluppo, inclusi i conteggi di tracciamento e allocazione per identificare i problemi di jank e ritardo nelle app. Puoi anche utilizzare Debug per ottenere contatori di tempo di esecuzione e memoria nativa e metriche di memoria che possono aiutarti a identificare il footprint della memoria di un determinato processo.

ApplicationExitInfo

ApplicationExitInfo è disponibile su Android 11 (livello API 30) o versioni successive e fornisce informazioni sul motivo dell'uscita dall'applicazione. Ciò include ANR, memoria insufficiente, arresti anomali delle app, utilizzo eccessivo della CPU, interruzioni utente, interruzioni del sistema e modifiche delle autorizzazioni di runtime.

Modalità più restrittiva

L'utilizzo di StrictMode ti aiuta a trovare operazioni di I/O accidentali nel thread principale durante lo sviluppo dell'app. Puoi utilizzare StrictMode a livello di applicazione o attività.

Attiva le finestre di dialogo ANR in background

Android mostra le finestre di dialogo ANR per le app che impiegano troppo tempo per elaborare il messaggio di trasmissione solo se l'opzione Mostra tutte le ANR è attivata nelle Opzioni per gli sviluppatori del dispositivo. Per questo motivo, le finestre di dialogo ANR in background non vengono sempre visualizzate all'utente, anche quando l'app riscontra problemi di prestazioni.

Colli di bottiglia della ricomposizione

Utilizza Android Studio Profiler e Layout Inspector per rilevare i colli di bottiglia della ricomposizione. Per saperne di più, consulta Prestazioni di Jetpack Compose.

Estrarre un file di tracce

Gli store Android tracciano le informazioni quando si verifica un errore ANR. Nelle versioni precedenti del sistema operativo, sul dispositivo è presente un unico file /data/anr/traces.txt. Nelle versioni più recenti del sistema operativo, sono presenti più file /data/anr/anr_*. Puoi accedere alle tracce ANR da un dispositivo o emulatore utilizzando Android Debug Bridge (adb) come root:

adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>

Puoi acquisire una segnalazione di bug da un dispositivo fisico utilizzando l'opzione per sviluppatori Acquisisci segnalazione bug sul dispositivo o il comando adb bugreport sul tuo computer di sviluppo. Per saperne di più, consulta Acquisire e leggere i report sui bug.

Risolvi i problemi

Una volta identificato il problema, puoi utilizzare i suggerimenti di questa sezione per risolvere i problemi più comuni.

Codice lento sul thread principale

Identifica i punti del codice in cui il thread principale dell'app è occupato per più di 5 secondi. Cerca i casi d'uso sospetti nella tua app e prova a riprodurre l'errore ANR.

Un problema comune è un'attività di lunga durata direttamente in un composable:

@Composable
fun BadList(rawStrings: List<String>) {
    // Math or sorting inside the composable runs on EVERY recomposition pass!
    val heavilyProcessedList = rawStrings
        .filter { it.isNotBlank() }
        .map { it.uppercase().reversed() }
        .map { it.computationallyHeavyFunction() }
.sortedBy { it.length }
    LazyColumn { items(sortedList) { Text(it) } }
}

// Modern Compose-first fix
@Composable
fun GoodList(viewModel: MyViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    // UI simply renders state; no heavy processing allowed here
    LazyColumn { items(uiState.sortedData) { Text(it) } }
}

I/O nel thread principale

L'esecuzione di operazioni di I/O sul thread principale è una causa comune di operazioni lente sul thread principale, che possono causare errori ANR. In Compose, gli sviluppatori spesso attivano accidentalmente letture del disco (come SharedPreferences o chiamate al database) mentre tentano di derivare lo stato iniziale.

Esegui operazioni di I/O a lunga esecuzione al di fuori del livello UI. Utilizza withContext(Dispatchers.IO) in un ViewModel o, ancora meglio, utilizza un Repository nel livello dati.

Deadlock

Si verifica un deadlock quando un thread entra in uno stato di attesa perché una risorsa richiesta è detenuta da un altro thread, che a sua volta è in attesa di una risorsa detenuta dal primo thread. Se il thread principale dell'app si trova in questa situazione, è probabile che si verifichino errori ANR.

I deadlock sono un fenomeno ben studiato in informatica ed esistono algoritmi di prevenzione dei deadlock che puoi utilizzare per evitarli.

Per saperne di più, consulta Deadlock e Algoritmi di prevenzione del deadlock su Wikipedia.

Quando utilizzi Kotlin e Compose, puoi sostituire i blocchi primitivi con Mutex di coroutine non bloccanti (Mutex.withLock) per evitare il blocco dei thread sospendendo il contesto di esecuzione anziché bloccare il thread dell'interfaccia utente. Ad esempio:

import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

// Modern non-blocking concurrency state architecture
class SecureDataRepository {
    private val mutex = Mutex()

    suspend fun safeUIAccess() {
        // If locked, the main thread suspends seamlessly, preventing an ANR
        mutex.withLock {
            performSafeOperation()
        }
    }
}

Broadcast receiver lenti

Le app possono rispondere ai messaggi di trasmissione, ad esempio attivando o disattivando la modalità aereo o una modifica dello stato della connettività, tramite i ricevitori di trasmissione. Un errore ANR si verifica quando un'app impiega troppo tempo per elaborare l'annuncio.

Un errore ANR si verifica nei seguenti casi:

  • Un broadcast receiver non ha terminato l'esecuzione del metodo onReceive entro un periodo di tempo considerevole.
  • Un broadcast receiver chiama goAsync e non riesce a chiamare finish sull'oggetto PendingResult.

La tua app deve eseguire solo operazioni brevi nel metodo onReceive di un BroadcastReceiver. Tuttavia, se la tua app richiede un'elaborazione più complessa a seguito di un annuncio, devi rimandare l'attività a un ViewModel (sfruttando la potenza di coroutine, ambiti e dispatcher Kotlin) se l'attività dovrebbe richiedere al massimo pochi secondi, a qualsiasi tipo di contenitore di stato o a WorkManager per le attività che dovrebbero richiedere più di pochi secondi.

GameActivity

La libreria GameActivity ha ridotto gli ANR negli studi di caso di giochi e app scritti in C o C++. Se sostituisci l'attività nativa esistente con GameActivity, puoi ridurre il blocco del thread dell'interfaccia utente ed evitare che si verifichino alcuni ANR.

Per saperne di più sugli errori ANR, vedi Mantenere la reattività dell'app. Per ulteriori informazioni sui thread, consulta Prestazioni migliori grazie ai thread.

Risorse aggiuntive

Visualizza contenuti

  • Nota: il testo del link viene visualizzato quando JavaScript è disattivato
  • Wakeup eccessivi