Android Studio fornisce un debugger che ti permette di fare quanto segue e altro ancora:
- Selezionare un dispositivo su cui eseguire il debug della tua app.
- Imposta punti di interruzione nel tuo codice Java, Kotlin e C/C++.
- Esamina le variabili e valuta le espressioni in fase di esecuzione.
Questa pagina include le istruzioni per le operazioni di base del debugger. Per ulteriore documentazione, vedi anche la documentazione sul debug di IntelliJ IDEA.
- Abilita il debug
- Avvia il debug
- Attacca il debugger a un’app in esecuzione
- Cambia il tipo di debugger
- Utilizza il log di sistema
- Scrivi messaggi di log nel tuo codice
- Visualizza il log di sistema
- Lavora con i punti di interruzione
- Visualizza e configura i punti di interruzione
- Finestra di debug frames
- Ispetta le variabili
- Aggiungi punti di osservazione
- Visualizza e cambia il formato di visualizzazione dei valori delle risorse
Abilita il debug
Prima di poter iniziare il debug, devi prepararti come segue:
- Abilita il debug sul tuo dispositivo:
Se stai usando l’emulatore, questo è abilitato di default. Ma per un dispositivo connesso, devi abilitare il debug nelle opzioni dello sviluppatore del dispositivo.
- Esegui una variante di build debuggabile:
Devi usare una variante di build che includa
debuggable true
nella configurazione di build. Di solito, puoi semplicemente selezionare la variante di default “debug” che è inclusa in ogni progetto Android Studio (anche se non è visibile nel filebuild.gradle
). Ma se definisci nuovi tipi di build che dovrebbero essere debuggabili, devi aggiungere “debuggable true” al tipo di build:android { buildTypes { customDebugType { debuggable true ... } }}
Questa proprietà si applica anche ai moduli con codice C/C++. (La proprietà
jniDebuggable
non è più utilizzata.)Se la tua applicazione dipende da un modulo di libreria di cui vuoi eseguire il debug, anche questa libreria deve essere impacchettata con
debuggable true
in modo da mantenere i suoi simboli di debug.Per assicurarti che le varianti debug del tuo progetto di app ricevano la variante debug di un modulo di libreria, assicurati di pubblicare versioni non di default della tua libreria.
Avvia il debug
Puoi iniziare una sessione di debug come segue:
- Imposta alcuni punti di interruzione nel codice dell’applicazione.
- Nella barra degli strumenti, seleziona un dispositivo su cui eseguire il debug della tua applicazione dal menu a discesa del dispositivo di destinazione.
Se non hai nessun dispositivo configurato, allora devi collegare un dispositivo via USB o creare un AVD per utilizzare l’emulatore Android.
- Nella barra degli strumenti, fai clic su Debug .
Se vedi una finestra di dialogo che ti chiede se vuoi “passare da Run a Debug”, significa che la tua applicazione è già in esecuzione sul dispositivo e si riavvierà per iniziare il debug. Se preferisci mantenere la stessa istanza dell’app in esecuzione, fai clic su Annulla Debug e collega invece il debugger a un’app in esecuzione.
Altrimenti, Android Studio costruisce un APK, lo firma con una chiave di debug, lo installa sul dispositivo selezionato e lo esegue. Se aggiungi codice C e C++ al tuo progetto, Android Studio esegue anche il debugger LLDB nella finestra Debug per eseguire il debug del tuo codice nativo.
- Se la finestra di Debug non è aperta, seleziona View > Tool Windows > Debug (o clicca su Debug nella barra della finestra degli strumenti), e poi clicca sulla scheda Debugger, come mostrato in figura 1.
Figura 1. La finestra Debugger, che mostra il thread corrente e l’albero degli oggetti per una variabile
Attacca il debugger a un’app in esecuzione
Se la tua app è già in esecuzione sul tuo dispositivo, puoi avviare il debug senza riavviare l’app come segue:
- Clicca su Attach debugger to Android process .
- Nella finestra di dialogo Choose Process, seleziona il processo a cui vuoi collegare il debugger.
Se stai usando un emulatore o un dispositivo con radici, puoi selezionare Mostra tutti i processi per vedere tutti i processi.
Dal menu a discesa Use Android Debugger Settings from, puoi selezionare una configurazione di esecuzione/debug esistente. (Per il codice C e C++, questo ti permette di riutilizzare i comandi di avvio LLDB, i comandi di post-attacco LLDB e le directory dei simboli in una configurazione esistente). Se non hai una configurazione di run/debug esistente, seleziona Create New. Questa selezione attiva il menu a discesa Tipo di debug, dove puoi selezionare un tipo di debug diverso. Per impostazione predefinita, Android Studio utilizza il tipo di debug automatico per selezionare la migliore opzione di debug per te, in base al fatto che il tuo progetto includa codice Java o C/C++.
- Clicca su OK.
Appare la finestra Debug.
Nota: il debugger di Android Studio e il garbage collector sono vagamente integrati. La macchina virtuale di Android garantisce che qualsiasi oggetto di cui il debugger è a conoscenza non sia garbage collector fino a quando il debugger non si disconnette. Questo può comportare un accumulo di oggetti nel tempo mentre il debugger è collegato. Per esempio, se il debugger vede un thread in esecuzione, l’oggetto Thread
associato non viene raccolto fino a quando il debugger si disconnette, anche se il thread è terminato.
Cambia il tipo di debugger
Perché sono necessari diversi strumenti di debugger per il debug del codice Java/Kotlin e del codice C/C++, il debugger di Android Studio ti permette di selezionare quale tipo di debugger utilizzare. Per impostazione predefinita, Android Studio decide quale debugger usare in base alle lingue che rileva nel tuo progetto (con il tipo di debuggerAuto). Tuttavia, puoi selezionare manualmente il debugger nella configurazione di debug (fai clic su Run > EditConfigurations) o nella finestra di dialogo che appare quando fai clic su Run > Attach debugger to Androidprocess.
I tipi di debug disponibili includono i seguenti:
Auto Seleziona questo tipo di debug se vuoi che Android Studio scelga automaticamente l’opzione migliore per il codice che stai debuggando. Per esempio, se hai del codice C o C++ nel tuo progetto, Android Studio usa automaticamente il tipo di debug Dual. Altrimenti, Android Studio usa il tipo di debug Java. Java Seleziona questo tipo di debug se vuoi eseguire il debug solo del codice scritto in Java o Kotlin – il debugger Java ignora qualsiasi breakpoint o watch che hai impostato nel tuo codice nativo. Native (disponibile solo con codice C/C++) Seleziona questo tipo di debug se vuoi usare solo LLDB per il debug del tuo codice. Quando si usa questo tipo di debug, la vista della sessione del debugger Java non è disponibile. Per impostazione predefinita, LLDB ispeziona solo il tuo codice nativo e ignora i punti di interruzione nel tuo codice Java. Se vuoi eseguire il debug anche del tuo codice Java, dovresti passare al tipo di debug Auto o Dual.
Il debug nativo funziona solo su dispositivi che soddisfano i seguenti requisiti:
-
Il dispositivo supporta
run-as
.Per controllare se il dispositivo supporta
run-as
, esegui il seguente comando sulla shell ADB collegata al tuo dispositivo:run-as your-package-name pwd
Sostituisci
your-package-name
con il nome del pacchetto della tua applicazione. Se il dispositivo supportarun-as
, il comando dovrebbe tornare senza errori. -
Il dispositivo ha
ptrace
abilitato.Per controllare se
ptrace
è abilitato, esegui il seguente comando sulla shell ADB collegata al tuo dispositivo:sysctl kernel.yama.ptrace_scope
Se
ptrace
è abilitato, il comando stamperà il valore0
o un erroreunknown key
. Septrace
non è abilitato, stamperà un valore diverso da0
.
Doppio (disponibile solo con codice C/C++) Seleziona questo tipo di debug se vuoi passare dal debug del codice Java a quello nativo. Android Studio collega sia il debugger Java che LLDB al processo della tua app, uno per il debugger Java e uno per LLDB, così puoi ispezionare i punti di interruzione sia nel tuo codice Java che in quello nativo senza riavviare la tua app o cambiare la tua configurazione di debug.
Nella figura 2, notate le due schede a destra del titolo della finestra di debug. Poiché l’applicazione ha sia codice Java che C++, una scheda è per il debug del codice nativo, e l’altra per il debug del codice Java, come indicato da -java.
Figura 2. Figura 2. Scheda per il debug del codice nativo e scheda per il debug del codice Java
Nota: Se state eseguendo il debug del codice nativo che è ottimizzato dal compilatore, potreste ricevere il seguente messaggio di avvertimento: This function was compiled with optimizations enabled. Some debugger features may not be available
. Quando si usano flag di ottimizzazione, come i flag -O
, il compilatore apporta modifiche al codice compilato per renderlo più efficiente. Questo può far sì che il debugger riporti informazioni inaspettate o errate perché è difficile per il debugger mappare il codice compilato ottimizzato nel codice sorgente originale. Per questo motivo, dovresti disabilitare le ottimizzazioni del compilatore durante il debug del tuo codice nativo.
Utilizza il log di sistema
Il log di sistema mostra i messaggi di sistema mentre esegui il debug della tua applicazione. Questi messaggi includono informazioni dalle applicazioni in esecuzione sul dispositivo. Se vuoi usare il log di sistema per il debug della tua applicazione, assicurati che il tuo codice scriva messaggi di log e stampi lo stacktrace per le eccezioni mentre la tua applicazione è in fase di sviluppo.
Scrivi messaggi di log nel tuo codice
Per scrivere messaggi di log nel tuo codice, usa la classe Log
. I messaggi di log ti aiutano a capire il flusso di esecuzione raccogliendo l’output di debug del sistema mentre interagisci con la tua applicazione. I messaggi di log possono dirvi quale parte della vostra applicazione è fallita. Per maggiori informazioni sui log, vedi Scrivere e visualizzare i log.
L’esempio seguente mostra come potresti aggiungere messaggi di log per determinare se le informazioni sullo stato precedente sono disponibili quando la tua attività inizia:
Durante lo sviluppo, il tuo codice può anche catturare le eccezioni e scrivere lo stack trace nel systemlog:
Nota: Rimuovi i messaggi di debug e le chiamate di stampa dello stack trace dal tuo codice quando sei pronto a pubblicare la tua applicazione. Puoi farlo impostando un DEBUG
flag e mettendo i messaggi di debug log all’interno di dichiarazioni condizionali.
Visualizza il log di sistema
Puoi visualizzare e filtrare il debug e altri messaggi di sistema nella finestra Logcat. Per esempio, puoi vedere i messaggi quando si verifica la garbage collection, o i messaggi che aggiungi alla tua app con la classe Log
.
Per usare logcat, avviate il debug e selezionate la scheda Logcat nella barra degli strumenti inferiore come mostrato in figura 3.
Figura 3. Figura 3. Finestra Logcat con le impostazioni dei filtri
Per una descrizione di logcat e delle sue opzioni di filtraggio, vedi Scrivere e visualizzare i log con Logcat.
Lavora con i punti di interruzione
Android Studio supporta diversi tipi di punti di interruzione che innescano diverse azioni di debug. Il tipo più comune è un punto di interruzione di linea che mette in pausa l’esecuzione della vostra applicazione in una specifica linea di codice. Durante la pausa, potete esaminare le variabili, valutare le espressioni, quindi continuare l’esecuzione riga per riga per determinare le cause degli errori di runtime.
Per aggiungere un punto di interruzione di riga, procedete come segue:
- Posizionate la riga di codice dove volete mettere in pausa l’esecuzione, quindi cliccate sul bordo sinistro lungo la riga di codice o posizionate il cestino sulla riga e premete Control+F8 (su Mac, Command+F8).
- Se la tua applicazione è già in esecuzione, non hai bisogno di aggiornarla per aggiungere il punto di interruzione: basta cliccare su Attach debugger to Android proccess . Altrimenti, avvia il debug cliccando su Debug .
Figura 3. Un punto rosso appare accanto alla linea quando imposti un punto di interruzione
Quando l’esecuzione del tuo codice raggiunge il punto di interruzione, Android Studio mette in pausa l’esecuzione della tua applicazione. Puoi quindi usare gli strumenti nella scheda Debugger per identificare lo stato dell’applicazione:
-
Per esaminare l’albero degli oggetti per una variabile, espandila nella vista Variabili. Se la vista Variabili non è visibile, fai clic su Restore Variables View .
-
Per valutare un’espressione al punto di esecuzione corrente, fate clic su Valuta espressione .
-
Per passare alla riga successiva del codice (senza inserire un metodo), fate clic su Passa oltre .
-
Per avanzare alla prima riga all’interno di una chiamata di metodo, fai clic su Step Into .
-
Per avanzare alla riga successiva al di fuori del metodo corrente, fai clic su Step Out .
-
Per continuare a eseguire l’applicazione normalmente, fai clic su Resume Program .
Se il tuo progetto usa del codice nativo, per default il tipo di debug Auto attacca sia il debugger Java che LLDB alla tua app come due processi separati, così puoi passare dall’ispezione dei breakpoint Java e C/C++ senza riavviare la tua app o cambiare le impostazioni.
Nota: affinché Android Studio rilevi i breakpoint nel tuo codice C o C++, devi usare un tipo di debug che supporti LLDB, come Auto, Native o Dual. Puoi cambiare il tipo di debug che Android Studio usa modificando la tua configurazione di debug. Per saperne di più sui diversi tipi di debug, leggi la sezione sull’uso di altri tipi di debug.
Quando Android Studio distribuisce la tua app sul dispositivo di destinazione, la finestra Debug si apre con una scheda o una vista della sessione di debug per ogni processo di debugger, come mostrato nella figura 4.
Figura 4. Debug del codice nativo usando LLDB
- Android Studio passa alla scheda <il tuo modulo> quando il debugger LLDB incontra un breakpoint nel tuo codice C/C++. I riquadri Frames, Variables e Watches sono anch’essi disponibili e funzionano esattamente come se steste debuggando il codice Java. Anche se il riquadro Threads non è disponibile nella vista di sessione LLDB, puoi accedere ai processi della tua applicazione usando l’elenco a discesa nel riquadro Frames. Puoi imparare di più su questi riquadri nelle sezioni su come fare il debug dei frame delle finestre e ispezionare le variabili.
Nota: mentre ispezioni un punto di interruzione nel tuo codice nativo, il sistema Android sospende la macchina virtuale che esegue il bytecode Java della tua applicazione. Questo significa che non sei in grado di interagire con il debugger Java o di recuperare qualsiasi informazione di stato dalla tua sessione di debugger Java mentre ispezioni un punto di interruzione nel tuo codice nativo.
- Android Studio passa alla scheda <il tuo modulo>-java quando il debugger Java incontra un breakpoint nel tuo codice Java.
- Mentre si esegue il debug con LLDB, è possibile utilizzare il terminale LLDB nella vista di sessione LLDB per passare opzioni della riga di comando a LLDB. Se hai certi comandi che vorresti che LLDB eseguisse ogni volta che avvii il debug della tua app, o appena prima o appena dopo che il debugger si attacchi al processo della tua app, puoi aggiungere questi comandi alla tua configurazione di debug.
Durante il debug del codice C/C++, puoi anche impostare speciali tipi di breakpoint, chiamati watchpoint, che possono sospendere il processo della tua applicazione quando questa interagisce con un particolare blocco di memoria. Per saperne di più, leggi la sezione su come aggiungere i watchpoint.
Visualizza e configura i punti di interruzione
Per visualizzare tutti i punti di interruzione e configurare le impostazioni dei punti di interruzione, fai clic su Visualizza punti di interruzione sul lato sinistro della finestra di debug. Appare la finestra Breakpoints, come mostrato in figura 5.
Figura 5. La finestra Breakpoints elenca tutti i breakpoints correnti e include le impostazioni di comportamento per ognuno
La finestra Breakpoints ti permette di abilitare o disabilitare ogni breakpoint dalla lista a sinistra. Se un punto di interruzione è disabilitato, Android Studio non mette in pausa la tua applicazione quando colpisce quel punto di interruzione. Seleziona un punto di interruzione dall’elenco per configurare le sue impostazioni. Puoi configurare un punto di interruzione per essere disabilitato all’inizio e fare in modo che il sistema lo abiliti dopo che viene colpito un punto di interruzione diverso. Puoi anche configurare se un punto di interruzione deve essere disabilitato dopo essere stato colpito. Per impostare un punto di interruzione per qualsiasi eccezione, seleziona Exception Breakpoints nell’elenco dei punti di interruzione.
Finestra di debug frames
Nella finestra Debugger, il pannello Frames ti permette di ispezionare il frame dello stack che ha causato il punto di interruzione corrente. Questo ti permette di navigare ed esaminare lo stack frame e anche di ispezionare l’elenco dei thread nella tua applicazione Android. Per selezionare un thread, usa il menu a tendina del selettore di thread e visualizza il suo stack frame. Facendo clic sugli elementi nel frame si apre il sorgente nell’editor. Puoi anche personalizzare la presentazione del thread ed esportare lo stack frame come discusso nella guida Window Frames.
Ispetta le variabili
Nella finestra Debugger, il pannello Variabili ti permette di ispezionare le variabili quando il sistema ferma la tua applicazione su un punto di interruzione e tu selezioni un frame dal pannello Frames. Il riquadro Variabili ti permette anche di valutare espressioni ad-hoc usando metodi statici e/o variabili disponibili all’interno del frame selezionato.
Il riquadro Orologi fornisce funzionalità simili, tranne che le espressioni aggiunte al riquadro Orologi persistono tra le sessioni di debug. Si dovrebbero aggiungere orologi per le variabili e i campi a cui si accede frequentemente o che forniscono uno stato utile per la sessione di debug corrente. I riquadri Variabili e Orologi appaiono come mostrato in figura 5.
Per aggiungere una variabile o un’espressione alla lista degli Orologi, seguite questi passi:
- Inizia il debug.
- Nel riquadro Orologi, fai clic su Aggiungi .
- Nella casella di testo che appare, digita il nome della variabile o dell’espressione che vuoi guardare e poi premi Invio.
Per rimuovere un elemento dalla lista Watches, selezionate l’elemento e poi cliccate su Remove .
Potete riordinare gli elementi nella lista Watches selezionando un elemento e poi cliccando su o giù .
Figura 6. I riquadri Variabili e Orologi nella finestra Debugger
Aggiungi punti di osservazione
Durante il debug del codice C/C++, puoi impostare speciali tipi di punti di interruzione, chiamati punti di osservazione, che possono sospendere il processo della tua applicazione quando questa interagisce con un particolare blocco di memoria. Per esempio, se impostate due puntatori a un blocco di memoria e gli assegnate un watchpoint, l’utilizzo di uno dei due puntatori per accedere a quel blocco di memoria fa scattare il watchpoint.
In Android Studio, potete creare un watchpoint durante il runtime selezionando una specifica variabile, ma LLDB assegna il watchpoint solo al blocco di memoria che il sistema alloca a quella variabile, non alla variabile stessa. Questo è diverso dall’aggiunta di una variabile al riquadro Orologi, che consente di osservare il valore di una variabile, ma non permette di sospendere il processo dell’applicazione quando il sistema legge o cambia il suo valore in memoria.
Nota: quando il vostro processo app esce da una funzione e il sistema dealloca le sue variabili locali dalla memoria, dovete riassegnare qualsiasi watchpoint che avete creato per quelle variabili.
Per impostare un watchpoint, dovete soddisfare i seguenti requisiti:
- Il vostro dispositivo fisico o emulatore di destinazione utilizza una CPU x86 o x86_64. Se il vostro dispositivo usa una CPU ARM, allora dovete allineare il confine dell’indirizzo della vostra variabile in memoria a 4 byte per i processori a 32 bit, o a 8 byte per i processori a 64 bit. Puoi allineare una variabile nel tuo codice nativo specificando
__attribute__((aligned(num_bytes)))
nella decelerazione della variabile, come mostrato di seguito:// For a 64-bit ARM processorint my_counter __attribute__((aligned(8)));
- Hai già assegnato tre o meno watchpoint. Android Studio supporta solo fino a quattro watchpoint su dispositivi di destinazione x86 o x86_64. Altri dispositivi potrebbero supportare meno watchpoint.
Nota: Quando si esegue il debug della propria applicazione con le ABI ARM a 32 bit, l’aggiunta di un watchpoint o il passaggio del mouse sulle variabili all’interno del codice per indagare sui loro valori può causare un crash. Come soluzione alternativa, esegui il debug utilizzando binari ARM, x86 o x86_64 a 64 bit. Questo problema sarà risolto in una prossima release di Android Studio.
Se soddisfi i requisiti di cui sopra, puoi aggiungere un watchpoint come segue:
- Mentre la tua app è sospesa su un breakpoint, passa al pannello Variabili nella tua vista di sessione LLDB.
-
Fate clic con il tasto destro del mouse su una variabile che occupa il blocco di memoria che volete monitorare e selezionate Add Watchpoint. Appare una finestra di dialogo per configurare il vostro watchpoint, come mostrato in figura 7.
Figura 7. Aggiunta di un watchpoint a una variabile in memoria
- Configura il tuo watchpoint con le seguenti opzioni:
- Abilitato: Puoi deselezionare questa opzione se vuoi dire ad Android Studio di ignorare il watchpoint per il momento. Android Studio salva comunque il tuo watchpoint in modo che tu possa accedervi più tardi nella tua sessione di debug.
- Sospendi: Per impostazione predefinita, il sistema Android sospende il processo della tua applicazione quando accede a un blocco di memoria che assegni a un watchpoint. Puoi deselezionare questa opzione se non vuoi questo comportamento – questo rivela ulteriori opzioni che puoi usare per personalizzare il comportamento quando il sistema interagisce con il tuo watchpoint: Log message to console e Remove when hit.
- Tipo di accesso: Selezionate se la vostra applicazione deve attivare il vostro watchpoint quando cerca di leggere o scrivere nel blocco di memoria che il sistema alloca alla variabile. Per attivare il vostro watchpoint sia in lettura che in scrittura, selezionate Any.
- Clicca su Done.
Per visualizzare tutti i tuoi punti di osservazione e configurare le impostazioni dei punti di osservazione, clicca su View Breakpoints sul lato sinistro della finestra di Debug. Appare la finestra di dialogo Breakpoints, come mostrato in figura 8.
Figura 8. La finestra di dialogo Breakpoints elenca i tuoi attuali watchpoints e include le impostazioni di comportamento per ognuno
Dopo aver aggiunto il tuo watchpoint, clicca su Resume Program sul lato sinistro della finestra di Debug per riprendere il processo della tua app. Per impostazione predefinita, se la tua app cerca di accedere a un blocco di memoria su cui hai impostato un watchpoint, il sistema Android sospende il processo della tua app e un’icona watchpoint appare accanto alla riga di codice che la tua app ha eseguito per ultima, come mostrato in figura 9.
Figura 9. Android Studio indica la riga di codice che la tua applicazione esegue appena prima di attivare un watchpoint
Visualizza e cambia il formato di visualizzazione dei valori delle risorse
In modalità debug, puoi visualizzare i valori delle risorse e selezionare un diverso formato di visualizzazione per le variabili nel tuo codice Java. Con la scheda Variabili visualizzata e un frame selezionato, fai quanto segue:
- Nell’elenco Variabili, fai clic con il tasto destro del mouse in qualsiasi punto di una riga di risorsa per visualizzare l’elenco a discesa.
- Nell’elenco a discesa, seleziona Visualizza come e seleziona il formato che vuoi usare.
I formati disponibili dipendono dal tipo di dati della risorsa che hai selezionato. Potresti vedere una o più delle seguenti opzioni:
- Classe: Visualizza la definizione della classe.
- toString: Visualizza il formato della stringa.
- Object: Visualizza la definizione dell’oggetto (un’istanza di una classe).
- Array: Visualizza in formato array.
- Timestamp: Visualizza data e ora come segue: yyyy-mm-dd hh:mm:ss.
- Auto: Android Studio sceglie il formato migliore in base al tipo di dati.
- Binary: Visualizza un valore binario usando zeri e uno.
- MeasureSpec: Il valore passato dal genitore al figlio selezionato. Vedere
MeasureSpec
. - Hex: Visualizza come un valore esadecimale.
- Primitive: Visualizza come un valore numerico usando un tipo di dati primitivo.
- Integer: Visualizza un valore numerico di tipo
Integer
.
È possibile creare un formato personalizzato (renderer del tipo di dati), come segue: