10 Minutes
Debugging in Android Studio: Tools, Techniques, and Workflow
Fix Bugs Faster! Log Collection Made Easy
Debugging Android apps can feel daunting given the sheer size of the ecosystem. However the suite of Android Studio debugging tools allows us to find, fix and prevent problems across our entire user base. Wherever they are, whichever devices they’re using.
This guide will give you a practical workflow to maximize the functionality of Android Studio, and empower you to debug Android apps from first breakpoint to production issues.
You’ll learn how to:
- Start a debugging session in Android Studio.
- Read frames, threads, variables, watches, and Logcat.
- Use breakpoints and step controls without guessing.
- Inspect runtime values and test fixes without recompiling.
- Diagnose performance issues with Android Profiler, a suite of performance analysis tools within Android Studio.
By the end, you’ll have a clear debugging flow you can use on real bugs.
Table of Contents
- What Android Studio debugging is
- How to start debugging in Android Studio
- Android Studio debugger interface overview
- Using breakpoints in Android Studio
- Inspecting variables and evaluating expressions
- Reading logs with Logcat
- Debugging performance with the Android Profiler
- Android Studio debugging best practices
- Debugging Android crashes in production
- Frequently asked questions about Android Studio debugging
- What is the difference between a debug and release build in Android?
- What is the difference between the Memory Profiler and LeakCanary?
- Can Android Studio debug an app already running on a device?
- Why does Android Studio skip my breakpoint?
- Can Android Studio debug Kotlin coroutines?
- Should I use Logcat or breakpoints first?
What Android Studio debugging is
Android Studio debugging allows us to check our app’s behavior in two distinct ways:
- Interactive debugging. Pausing execution with the debugger, breakpoints, variables, watches, and step controls.
- Observational debugging. Reading Logcat, crash reports and data from Android Profiler without stopping the app.
Most real debugging regimes move seamlessly between both. We pause the app when we need the exact runtime state, and we observe logs or profiler data when stopping execution would hide the issue.
Under the hood, Android Studio uses Java Debug Wire Protocol (JDWP) ****for Java and Kotlin debugging, and LLDB for native C/C++ debugging. This really becomes important when the app uses native code through the Native Development Kit (NDK).
How to start debugging in Android Studio
To start debugging in Android Studio, simply run the app with the Debug button instead of the normal Run button. This starts the app, connects the debugger, and opens the debug tools when execution pauses.
- Open the project. Start Android Studio and open the Android app you want to debug.
- Choose a device. Use the device dropdown in the top toolbar to select a connected Android phone or emulator.
- Open the relevant file. Go to the Activity, Fragment, ViewModel, or function where the bug may be happening.
- Set a breakpoint. Click the empty gutter area to the left of the line number. A red dot means the breakpoint is active.
- Start debug mode. Click the green bug icon in the top toolbar. On macOS, you can also press Control + D.
Android Studio debugger interface overview

Once the debugger has attached, Android Studio will open the debugger interface at the bottom of the IDE. This is where we control execution and inspect the paused app.
| Debugger area | What it shows |
|---|---|
| Frames | The call stack that led to the current paused line. |
| Threads | Which parts of the app are currently running, waiting, or paused. |
| Variables | Values available in the current scope, including local variables and method arguments. |
| Watches | Selected variables or expressions we want to track while stepping through code. |
| Logcat | Live app and system logs, with filters for package, tag, and log level. |
Using breakpoints in Android Studio
A breakpoint pauses app execution at a specific line, so you can drill down and inspect particular objects, collections and variables before the app continues running. Here’s how to set one up:
- Click the line number gutter in any Kotlin or Java file to set one. A red dot confirms it is active.
- When execution hits the breakpoint, the debugger panel opens and shows the current variables and call stack.
- From here, use step controls to move through code.
Android Studio supports several breakpoint types beyond basic line breakpoints: conditional breakpoints, method breakpoints, field watchpoints, and exception breakpoints. Each serves a different diagnostic purpose.
For a full guide to every breakpoint type and how to use advanced options like conditions and logging actions, take a look at our dedicated Android Studio breakpoints article.
Stepping through code in the debugger
Once execution pauses, you can use these four distinct controls in the debugger toolbar to move forward.
| Control | What it does |
|---|---|
| Resume | Resumes execution until the next breakpoint |
| Step Over | Executes the current line without entering any called methods |
| Step Into | Enters the method called on the current line |
| Step Out | Finishes the current method and returns to the caller |
Step Over is the default choice for moving through logic quickly, while Step Into allows you to follow execution into a specific method call.
Step Out allows you to leave a method you’ve already finished inspecting, without having to manually step through every remaining line of code.
Inspecting variables and evaluating expressions
One of the most powerful features of Android Studio debugging is the ability to evaluate expressions and modify variable values during a paused session, without recompiling. This is great for testing hypotheses, exploring different execution paths and validating fixes before you implement them.
Two ways to do it:
- Press Alt+F8 (or use Run > Evaluate Expression) to open a dialog where you can type any valid Kotlin or Java expression and see the result immediately.
- In the variables view, double-click any primitive value to edit it directly during the paused session.
The Evaluate Expression dialog supports full expressions, including method calls and object creation. If you suspect a null check is wrong, you can test the correct condition live and confirm the fix before writing a single line.
Reading logs with Logcat

Logcat is Android Studio’s live log stream. We use it when we need to see app messages, system output, exceptions, crashes, or ANR reports without pausing the app.
To open Logcat, go to View > Tool Windows > Logcat or select the Logcat tab in the bottom tool window area.
The fastest workflow is:
- Select the running app – choose the app process from the Logcat process dropdown.
- Filter by package – limit output to the current app so system noise does not hide the useful logs.
- Choose a log level – start with Warning or Error for crashes, then widen to Info or Debug if needed.
- Search by tag or keyword – look for exception names, screen names, request IDs, or custom log tags.
- Reproduce the issue – use the app again and watch which logs appear before the bug.
Logcat is especially useful for lifecycle issues, background work, network failures, and bugs where pausing execution would change the behavior.
Debugging performance with the Android Profiler

The Android Profiler helps us debug performance problems that do not show up clearly in breakpoints or Logcat. You can use it when the app feels slow, memory keeps growing, the UI stutters, or battery usage looks suspicious.
To open it: go to View > Tool Windows > Profiler, or click the Profiler tab at the bottom of the IDE while the app is running.
The most useful Profiler tasks depend on the bug we are trying to confirm.
Main functions of the Android Profiler
The Profiler panel shows these tasks from left to right:
| Common profiling task | What to do |
|---|---|
| Analyze Memory Usage | Use this when the app slows down over time or crashes after repeated navigation. Capture a heap dump and check which objects are still in memory. |
| View Live Telemetry | Start here when you need a quick overview. Monitor CPU, memory, network, and energy while using the app, then look for spikes when the issue happens. |
| Capture System Activities | Use this when the UI stutters, freezes, or drops frames. Record a short trace while reproducing the issue, then inspect thread activity and rendering delays. |
| Track Memory Consumption | Use this when one screen or action seems to create too many objects. Record the flow, then look for repeated allocations that keep growing. |
| Find CPU Hotspots | Use this when taps, scrolling, or screen loading feels delayed. Record the slow flow, then check which methods take the most time. |
But remember: If you want to carry out serious performance debugging, use a real device. The emulator is useful for quick checks, but it does not always match real CPU, memory, graphics, or thermal behavior.
Android Studio debugging best practices
We’ve covered all the most important tools that Android Studio offers. But if you want to save debugging time, these tips will be more effective than any single feature or function.
- Use debug builds. Debug builds allow the debugger to attach, while release builds may use R8/ProGuard to shrink, optimize, and obfuscate code.
- Filter Logcat immediately. Unfiltered Logcat is too noisy to read; set a package filter as soon as a session starts.
- Set exception breakpoints by default. An Any Exception breakpoint will surface crashes at the throw site, not the catch site.
- Use the Memory Profiler before assuming a leak. Never diagnose memory issues from symptoms alone. Capture a heap dump first and confirm the leak exists.
- Profile before optimizing. Run the CPU Profiler before touching performance-critical code. Optimize what the data shows, not what you suspect.
- Test on real devices. The emulator does not replicate manufacturer-specific behavior, thermal throttling, or real-world memory pressure.
Debugging Android crashes in production
Android Studio’s debugger works only when a device is connected and running a debug build. Once the app ships to the Play Store, we lose direct debugger access.
Production crashes usually appear in Android Vitals or Google Play Console. These reports show where the crash occurred, plus details like device model, Android version, stack trace, and ANR data.
What these reports usually miss is context.
Stack traces rarely show the user actions, network responses, lifecycle events, or state changes that led to the crash. Device fragmentation makes this harder, because a bug on one Android version or manufacturer ROM may be difficult to reproduce locally.
For command-line device diagnostics, see our ADB debugging article.
And of course… you can use Bugfender
Bugfender is our very own tool, but we think it’s relevant here.
Bugfender captures logs from real user sessions, so we can see what happened before a crash without needing physical access to the device.
Try Bugfender for free and start collecting logs in under five minutes.
Frequently asked questions about Android Studio debugging
What is the difference between a debug and release build in Android?
A debug build includes debugging information and allows the debugger to attach. A release build is optimized for distribution and may use R8/ProGuard to shrink, optimize, and obfuscate code.
If a crash only appears in a release build, the cause may be code shrinking, obfuscation, missing keep rules, or behavior that only happens with release settings enabled.
What is the difference between the Memory Profiler and LeakCanary?
The Memory Profiler is built into Android Studio and gives you a visual real-time view of heap allocations and the ability to capture heap dumps on demand. LeakCanary is an open-source library that automatically detects and reports specific retain cycles at test time. Use both: LeakCanary catches leaks automatically during development; the Memory Profiler helps you investigate them in detail.
Can Android Studio debug an app already running on a device?
Yes. Android Studio can attach the debugger to an already running app if the app is debuggable. Use Run > Attach Debugger to Android Process, then select the app process from the list.
Why does Android Studio skip my breakpoint?
Android Studio usually skips a breakpoint when the line is not executed, the running build does not match the source code, or the breakpoint is set on code optimized away by the build. Rebuild the app, confirm the right device is selected, and test the exact code path again.
Can Android Studio debug Kotlin coroutines?
Yes. Android Studio can debug Kotlin coroutines, but coroutine bugs can be harder to follow because execution may move between threads. Use breakpoints, the coroutine debugger view when available, and Logcat to track job state, cancellation, and dispatcher changes.
Should I use Logcat or breakpoints first?
Use Logcat first when the bug depends on timing, lifecycle events, background work, or production-like behavior. Use breakpoints when we need to pause execution and inspect exact runtime state. In practice, we usually use both.
Expect The Unexpected!
Debug Faster With Bugfender