Introdução à depuração

Qualquer pessoa que usou um software provavelmente já encontrou um bug. Um bug é um erro em um software que causa um comportamento não intencional, como uma falha no app ou um recurso que não funciona como esperado. Independentemente da experiência, todos os desenvolvedores geram bugs ao escrever códigos. Uma das habilidades mais importantes para um desenvolvedor Android é identificar e corrigir esses problemas. Não é incomum ver versões inteiras de apps dedicadas a corrigir bugs. Por exemplo, veja os detalhes da versão do Google Maps abaixo:

9d5ec1958683e173.png

O processo de correção de bugs é chamado de depuração. O famoso cientista da computação Brian Kernighan uma vez disse que "a ferramenta de depuração mais eficaz ainda é uma reflexão cuidadosa, junto com instruções de impressão bem colocadas." Embora isso com certeza seja verdade, ferramentas de depuração mais sofisticadas podem ajudar a encontrar bugs com mais rapidez e facilidade. Embora a depuração, assim como a programação, é uma habilidade que você desenvolverá com o tempo, nunca é cedo para se familiarizar com as ferramentas de depuração integradas ao Android Studio. Nesta lição, você conhecerá o depurador integrado do Android Studio e aprenderá a ler stack traces e a analisar código usando pontos de interrupção.

Pré-requisitos

  • Saber navegar em um projeto no Android Studio.

O que você aprenderá

  • Como anexar o depurador ao app em execução.
  • Como encontrar informações significativas em um stack trace.
  • Usar pontos de interrupção para pausar um app em execução e inspecionar o código, uma linha por vez.

O que é necessário

  • Um computador com o Android Studio instalado.

Em vez de depurar um app grande e complexo, começaremos com um projeto em branco e acrescentaremos um código com bugs para ajudar a demonstrar as ferramentas de depuração no Android Studio.

Comece criando um novo projeto do Android Studio, como mostrado.

  1. Na tela Select a Project Template selecione Blank Activity.

a949156bcfbf8a56.png

  1. Nomeie o app como Depuração. Verifique se a linguagem está definida como Kotlin e se todo o restante está inalterado.

9863157e10628a87.png

  1. Você verá um novo projeto do Android Studio que mostra um arquivo chamado MainActivity.kt.

e3ab4a557c50b9b0.png

Como criar um bug

Não há muita depuração para fazer em um projeto em branco. Vamos adicionar um código que cause falhas no app.

Você se lembra de aprender na aula de matemática que não é possível dividir um número por zero? Vejamos o que acontece quando tentamos dividir por zero no código.

  1. Abra MainActivity.kt e adicione a função abaixo. Esse código começa com dois números e usa repeat para imprimir o resultado da divisão do numerador pelo denominador cinco vezes. Cada vez que o código no bloco repeat é executado, o valor de denominator é reduzido em um. Na quinta e última iteração, o app tentará dividir por zero.
fun division() {
    val numerator = 60
    var denominator = 4
    repeat(5) {
        println(numerator / denominator)
        denominator--
    }
}
  1. Chame a função division() em onCreate(). A nova função onCreate() precisa ter a seguinte aparência.
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    division()
}
  1. Execute o app. Como o onCreate() será executado assim que o primeiro aparecer, é possível que o app falhe logo após a inicialização. Quando um app falha, informações úteis são fornecidas para ajudar a localizar o erro.
  2. Abra a guia Logcat na parte inferior do Android Studio. Ela poderá levar algum tempo para ser carregada se estiver sendo aberta pela primeira vez.

e4d025b0363eaa63.png

  1. A janela do Logcat mostra muitas saídas. Portanto, talvez seja necessário rolar um pouco a tela para encontrar as outras. Para garantir que apenas a saída do seu app seja exibida, defina o menu suspenso no canto superior esquerdo como o nome do emulador (ou dispositivo físico) e o processo como seu app (com.example.debugging).

5c008135b1804091.png

  1. Pesquise a mensagem de erro (Control+F no Windows, Command+F no Mac) digitando "RuntimeException" na caixa de pesquisa e pressione Enter.

9468226e5f4d5729.png

Anatomia de um stack trace

O bloco de texto que descreve a exceção é chamado de stack trace. O stack trace mostra todas as funções que foram chamadas, levando à exceção, começando pela chamada mais recente. A saída completa é mostrada abaixo.

Process: com.example.debugging, PID: 23296
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.debugging/com.example.debugging.MainActivity}: java.lang.ArithmeticException: divide by zero
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.ArithmeticException: divide by zero
        at com.example.debugging.MainActivity.division(MainActivity.kt:17)
        at com.example.debugging.MainActivity.onCreate(MainActivity.kt:10)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

É uma grande quantidade de texto. Por sorte, você normalmente só precisa de algumas partes para restringir ao erro exato. Vamos começar do início.

  1. java.lang.RuntimeException:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.debugging/com.example.debugging.MainActivity}: java.lang.ArithmeticException: divide by zero

A primeira linha indica que o app não conseguiu iniciar a atividade, e é esse o motivo da falha. A próxima linha traz um pouco mais de informações. Especificamente, não foi possível iniciar a atividade devido a uma ArithmeticException. Mais especificamente, o tipo de ArithmeticException era "divide by zero" (dividir por zero).

  1. Caused by:
Caused by: java.lang.ArithmeticException: divide by zero
        at com.example.debugging.MainActivity.onCreate(MainActivity.kt:17)

Ao rolar para baixo até a linha "Caused by" (Causado por), novamente você verá um erro "divide by zero". Desta vez, ele também mostra a função exata em que o erro ocorreu (division()) e o número da linha exata (17).

Nenhuma dessas situações é uma surpresa, já que o bug foi introduzido intencionalmente. No entanto, se você precisar determinar a causa de um erro desconhecido, saber o tipo exato de exceção, o nome da função e o número da linha fornecerá informações muito úteis.

No exemplo anterior, você viu como o stack trace forneceu informações específicas sobre o erro, como a função e a linha de código em que ele ocorreu. Ao trabalhar com bugs reais, isso pode não ser suficiente para determinar uma correção. Por exemplo, mesmo que você saiba onde o bug foi introduzido no código (linha 17) e qual foi o erro exato (dividir por zero), talvez não saiba por que seu código estava dividindo um número por zero. Nesse caso, você pode adicionar instruções println() antes que a divisão ocorra na função division() para imprimir o valor de denominator que está sendo usado como o denominador.

fun division() {
    val numerator = 60
    var denominator = 4
    repeat(5) {
        println(denominator)
        println(numerator / denominator)
        denominator--
    }
}

Obviamente, se o problema for mais complexo, será necessário adicionar instruções println() e executar o app novamente até encontrar algo útil. Isso pode ser difícil de rastrear à medida que seu código se torna mais complexo.

É aqui que entra em cena algo chamado pontos de interrupção. Embora Brian Kernighan possa estar certo sobre o valor de uma declaração de impressão bem posicionada, um ponto de interrupção tem uma finalidade similar, mas é mais semelhante a pressionar um botão de pausa no app em execução. É possível definir um ponto de interrupção em praticamente qualquer linha de código. Quando um ponto de interrupção é atingido, todas as execuções são interrompidas, e é possível inspecionar os valores das variáveis ou até mesmo percorrer o código executando apenas uma linha por vez. Para usar pontos de interrupção, execute o app usando algo chamado depurador.

Como anexar o depurador

Em segundo plano, o Android Studio usa uma ferramenta chamada Android Debug Bridge (ou apenas ADB). Essa é uma ferramenta de linha de comando integrada ao Android Studio que oferece recursos de depuração, como pontos de interrupção, aos apps em execução. Uma ferramenta de depuração costuma ser chamada de depurador.

Para usar (ou anexar) o depurador em um app, não é possível simplesmente executar o app em Run > Run como antes. Em vez disso, execute o app com Run > Debug ‘app'.

21d706a854ebe710.png

Adicionar pontos de interrupção ao seu projeto

Siga as etapas abaixo para ver os pontos de interrupção em ação.

  1. Adicione um ponto de interrupção clicando no espaço em branco ao lado do número da linha que você quer pausar. Um ponto será exibido ao lado do número da linha, que será destacada.

6b6c2cd97bdc08ba.png

  1. Execute o app com o depurador anexado usando Run > Debug ‘app' ou o ícone f6a141c7f2a4e444.png na barra de ferramentas. Quando o app for iniciado, você verá uma tela como esta.

3bd9cbe69d5a0d0e.png

Depois que o app for iniciado, você verá o ponto de interrupção destacado quando ele for ativado.

a4860e59534f216a.png

Uma nova guia Debug será aberta na parte inferior da tela em que você visualizava a janela do Logcat.

ce37d2791db7302.png

À esquerda, há uma lista de funções (a mesma que apareceu no stack trace) e, no lado direito, há um painel em que é possível verificar os valores de variáveis individuais. Há também alguns botões na parte superior que ajudarão você a navegar no programa enquanto ele estiver pausado. O que você usará com mais frequência é Step Over, que executa a linha de código destacada.

a6c07c89e81abdc5.png

Realize as etapas a seguir para depurar o código.

  1. Depois que o ponto de interrupção for alcançado, a linha 14 (que declara a variável numerator) ficará destacada, mas ainda não terá sido executada. Use o botão Step Over 1d02d8134802ee64.png para executar a linha 14. Agora a linha 15 ficará em destaque.

58f4bb135d5b756e.png

  1. Defina um ponto de interrupção na linha 17. Esse é o local em que a divisão ocorreu e é a linha em que o stack trace informou a exceção.

88d7d810a29965aa.png

  1. Use o botão Resume Program 8119afebc5492126.png à esquerda da janela Debug para ir até o próximo ponto de interrupção e executar o restante da função division().

433d1c2a610b7945.png

  1. Observe que a execução é interrompida na linha 17 antes de executá-la.

1f6aedcf2a48c492.png

  1. Os valores de cada variável (numerator e denominator) são mostrados ao lado das declarações delas. Observe como os valores das variáveis também podem ser vistos na janela de depuração da guia Variables.

ebac20924bafbea5.png

  1. Pressione o botão Resume Program à esquerda da janela de depuração mais quatro (4) vezes e pause cada vez para observar os valores de numerator e denominator. Na última iteração, numerator precisa ser 60 e denominator precisa ser 0. E não é possível dividir 60 por 0.

246dd310b7fb54fe.png

Agora você sabe a linha de código exata que está causando o bug e o motivo exato disso. Na quinta iteração, o valor de denominator é 0. Para corrigir esse erro, adicione uma instrução if que executará a divisão somente se denominator NÃO for igual a 0.

fun division() {
    val numerator = 60
    var denominator = 4
    repeat(5) {
        if (denominator != 0) {
            println(numerator / denominator)
        }
        denominator--
    }
}

Também é possível mudar o número de vezes que o código será repetido de 5 para 4.

fun division() {
    val numerator = 60
    var denominator = 4
    repeat(5) {
        println(numerator / denominator)
        denominator--
    }
}

Qualquer uma dessas abordagens permitirá executar o código sem causar exceções de tempo de execução. Teste e veja.

Nas lições anteriores, você usou a instrução println() do Kotlin para produzir saída de texto. Em um app Android, a prática recomendada para gerar registros de saída é usar Log. Há várias funções para gerar registros de saída, no formato Log.e() ou Log.d() e com dois parâmetros: o primeiro, chamado de "tag", é uma string que identifica a origem da mensagem de registro (como o nome da classe que registrou o texto). A segunda é a mensagem de registro real.

Há diferentes funções de registro, nomeadas com letras diferentes, porque elas correspondem a níveis de registro distintos. Dependendo do tipo de informação que você quer gerar, use um nível de registro diferente para filtrá-la na saída de Logcat. Existem cinco níveis principais de registro que você usará com frequência.

Nível de registro

Caso de uso

Exemplo

ERROR

Registros de ERROR (erro) relatam que algo deu errado, como o motivo de um app ter falhado.

Log.e(TAG, "The cake was left in the oven for too long and burned.").

WARN

Os registros de WARN (aviso) são menos graves que um erro, mas ainda relatam algo que precisa ser corrigido para evitar um erro mais grave. Um exemplo pode ser se você chamar uma função descontinuada, o que significa que é recomendável usar uma alternativa mais recente.

Log.w(TAG, "This oven does not heat evenly. You may want to turn the cake around halfway through to promote even browning.")

INFO

Os registros de INFO (informações) fornecem informações úteis, como uma operação ter sido concluída. Esse é o nível de registro de uma instrução println().

Log.i(TAG, "The cake is ready to be served.").println("The cake has cooled.")

DEBUG

Os registros de DEBUG (depuração) contêm informações que podem ser úteis ao investigar um problema.

Log.d(TAG, "Cake was removed from the oven after 55 minutes. Recipe calls for the cake to be removed after 50 - 60 minutes.")

VERBOSE

Como o nome indica, são registros detalhados. O que é considerado um registro de depuração, em vez de um registro detalhado, é um pouco subjetivo. Geralmente, um registro detalhado é algo que pode ser removido após a implementação de um recurso, enquanto que um registro de depuração ainda pode ser útil para depuração.

Log.v(TAG, "Put the mixing bowl on the counter.")Log.v(TAG, "Grabbed the eggs from the refrigerator.")Log.v(TAG, "Plugged in the stand mixer.")

Lembre-se de que não há regras válidas sobre quando usar cada tipo de nível de registro, especialmente quando usar INFO, DEBUG e VERBOSE. As equipes de desenvolvimento de software podem criar as próprias diretrizes sobre quando usar cada nível de registro ou decidir não usar determinados níveis, como VERBOSE.

Veja como são esses diferentes níveis de registro no Logcat.

  1. Em MainActivity.kt, antes da declaração de classe, adicione uma constante chamada TAG e defina o valor dela como o nome da classe, MainActivity.
private const val TAG = "MainActivity"
  1. Adicione uma nova função à classe MainActivity, chamada logging(), conforme mostrado.
fun logging() {
    Log.e(TAG, "ERROR: a serious error like an app crash")
    Log.w(TAG, "WARN: warns about the potential for serious errors")
    Log.i(TAG, "INFO: reporting technical information, such as an operation succeeding")
    Log.d(TAG, "DEBUG: reporting technical information useful for debugging")
    Log.v(TAG, "VERBOSE: more verbose than DEBUG logs")
}
  1. Substitua a chamada para division() (do exemplo anterior) em onCreate() por uma chamada para logging(). O novo método onCreate() ficará como mostrado a seguir.
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    logging()
}
  1. Execute seu app e observe a saída no Logcat. Se necessário, filtre a saída para mostrar apenas os registros do processo com.example.debugging. Também é possível filtrar a saída para mostrar apenas registros com a tag "MainActivity". Para fazer isso, selecione "Edit Filter Configuration" no menu suspenso no canto superior direito da janela do Logcat.

5fa189e6b18a966a.png

  1. Em seguida, digite "MainActivity" em Log Tag e crie um nome para o filtro, conforme mostrado.

6dbba17eb5df15eb.png

  1. Agora você verá apenas mensagens de registro com a tag "MainActivity".

4061ca006b1d278c.png

Observe que há uma letra antes do nome da classe (por exemplo, W/MainActivity) correspondente ao nível de registro. Além disso, o registro WARN é exibido em azul, enquanto o registro ERROR é exibido em vermelho, assim como o erro fatal no exemplo anterior.

  1. Assim como você pode filtrar a saída de depuração por processo, também é possível filtrar a saída por nível de registro. Por padrão, essa opção está definida como Verbose, que mostrará os registros VERBOSE e níveis mais altos. Selecione Warn no menu suspenso e veja que agora apenas os registros de nível WARN e ERROR são mostrados.

c4aa479a8dd9d4ca.png

  1. Mude o menu suspenso para Assert e observe que nenhum registro é exibido. Isso filtra tudo que está no nível ERROR e abaixo.

169a0bc232f77734.png

Embora isso possa parecer uma preocupação um pouco excessiva com as instruções printIn(), conforme você cria apps maiores, a saída do Logcat será muito maior, e usar diferentes níveis de registro permitirá a seleção das informações mais úteis e relevantes. O uso de registros é considerado uma prática recomendada e é preferível do que usar println() no desenvolvimento para Android. Escolher o nível de registro correto beneficiará outros membros da equipe de desenvolvimento que não estão familiarizados com o código e facilitará muito a identificação e a solução de bugs.

Por padrão, o modelo Blank Activity usado para criar o projeto adiciona uma única atividade, com uma TextView centralizada na tela. Como você aprendeu anteriormente, é possível referenciar visualizações pelo código, definindo um ID no editor de layout e acessando a visualização com findViewByID(). Vamos tentar acessar a visualização para ajudar a ilustrar outro bug.

  1. Abra activity_main.xml, selecione Hello, world! , que é a TextView, e defina o ID como hello_world.

8a5dede436e2718e.png

  1. Em seguida, volte para ActivityMain.kt em onCreate(), adicione o código para receber a TextView e mude o texto dela para "Hello, debugging!" antes da chamada para setContentView().
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val helloTextView: TextView = findViewById(R.id.hello_world)
    helloTextView.text = "Hello, debugging!"
    setContentView(R.layout.activity_main)
    division()
}
  1. Execute o app novamente e observe que ele falha imediatamente após a inicialização. Filtre os registros por com.example.debugging.

cdb335255d798a0a.png

A exceção precisa ser uma das últimas coisas que aparecem no Logcat (se não, você pode pesquisar RuntimeException). A saída será semelhante à seguinte.

com.example.debugging E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.debugging, PID: 5516
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.debugging/com.example.debugging.MainActivity}: java.lang.IllegalStateException: findViewById(R.id.hello_world) must not be null
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.IllegalStateException: findViewById(R.id.hello_world) must not be null
        at com.example.debugging.MainActivity.onCreate(MainActivity.kt:10)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

Como antes, a mensagem "Unable to start activity" (Não foi possível iniciar a atividade) aparece na parte superior. Isso faz sentido porque o app falhou antes do lançamento da MainActivity. A linha a seguir mostra um pouco mais sobre o erro.

java.lang.IllegalStateException: findViewById(R.id.hello_world) must not be null

Mais abaixo no stack trace, você também verá essa linha mostrando a chamada de função e o número da linha exatos.

Caused by: java.lang.IllegalStateException: findViewById(R.id.hello_world) must not be null
        at com.example.debugging.MainActivity.onCreate(MainActivity.kt:10)

O que exatamente significa esse erro e o que é exatamente um valor "nulo"? Embora esse seja um exemplo fictício e você já tenha uma ideia do motivo da falha do app, inevitavelmente encontrará mensagens de erro que não viu antes. Quando isso acontece, é provável que você não seja o primeiro a ver o erro. Até mesmo os desenvolvedores mais experientes costumam pesquisar mensagens de erro no Google para ver como os outros resolveram o problema. Buscar esse erro gera vários resultados no StackOverflow, um site em que os desenvolvedores podem fazer perguntas e dar respostas sobre códigos com bugs ou tópicos de programação mais gerais.

efa074b344d1704c.png

Se você ler algumas das respostas, perceberá que o erro pode ter várias causas diferentes. No entanto, se comparar nosso exemplo com o código da unidade 1, você perceberá que tentamos deliberadamente acessar uma visualização antes da chamada para setContentView(). A tentativa de acessar a visualização antes que ela tenha existido causou a exceção de tempo de execução.

Para corrigir o erro, atualize o código.

  1. Mova a chamada para findViewById() e a linha que define o texto de helloTextView abaixo da chamada para setContentView(). O novo método onCreate() será semelhante ao seguinte.
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)
   val helloTextView: TextView = findViewById(R.id.hello_world)
   helloTextView.text = "Hello, debugging!"
   division()
}
  1. Em seguida, execute novamente o app, observe que o código não falha mais e o texto é atualizado conforme o esperado.

e52adf1c7bf6f792.png

Resumindo:

  • A depuração é o processo de solucionar os bugs no seu código.
  • O stack trace fornece informações sobre uma exceção, como a função exata que a causou e o número da linha em que a exceção ocorreu.
  • É possível definir pontos de interrupção para pausar a execução do seu app.
  • Quando a execução estiver pausada, você poderá usar "step over" para executar uma única linha de código.

Saiba mais