Expert: features and shipping · Testing Android apps · topic 42 of 50 · 30 min
Debugging and performance
Explanation
Debugging is a method, not luck
When something goes wrong, guessing wastes hours. A calm method works: reproduce the bug reliably, read the error or log, form a guess, check it with a tool, fix, and add a test so it cannot return. Android Studio gives you strong tools for each step.
Logcat, used well
Filter Logcat to your app (package:mine), your tag (tag:Cart) and level (level:error). Log key events with clear messages: "Checkout started, items=3". Never log passwords, OTPs, tokens or personal data, even in debug builds, because logs can be read during development and shared in bug reports.
The debugger
- Click in the gutter next to a line to set a breakpoint (a red dot).
- Run the app with the Debug button (the bug icon) instead of Run.
- When the line is reached, the app pauses. The Variables panel shows every value at that moment.
- Step Over goes to the next line; Step Into enters a function; Resume continues to the next breakpoint.
- Right-click a breakpoint to add a condition, for example only stop when orderId == 9081.
The debugger answers "what is actually happening" directly, instead of adding and removing dozens of log lines. You can also attach the debugger to an app that is already running.
Layout Inspector
Layout Inspector shows the live UI tree of a running app: every composable, its size and parameters. For Compose it can also show recomposition counts, how many times each composable re-ran. If a small Text recomposes hundreds of times while you scroll, something reads state too broadly; fix it before users feel the lag.
Profiler
The Android Studio Profiler measures CPU usage (which functions take the time), memory (allocations and leaks) and more while the app runs. Use it when a screen stutters or the app gets slower over time. Measure first, then optimise the part that is actually slow.
Common performance fixes in Compose
| Symptom | Likely cause | Fix |
|---|---|---|
| Scrolling a long list stutters | Column with all items, or no keys | LazyColumn with key = { it.id } |
| Screen janks on every state change | Heavy work (sorting, formatting) inside the composable body | Do it in the ViewModel, or remember(input) { compute(input) } |
| Many recompositions while scrolling | Reading fast-changing state high in the tree | Read state as low as possible; use derivedStateOf for derived values |
| Slow first launch | Heavy work in onCreate or Application | Load lazily; consider Baseline Profiles |
Baseline Profiles
A Baseline Profile is a list of the app's important code paths (start-up, first screen, scrolling) that ships with the app so Android can compile them ahead of time on install. Google reports noticeably faster start-up and smoother first frames for apps that use them. They are generated with the Macrobenchmark library; treat them as an expert optimisation after the basics.
Common mistakes
- Measuring speed in debug builds and "optimising" code that is fast in release.
- Optimising without measuring first.
- Logging sensitive data.
- Fixing a bug without adding a test, so it comes back later.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Debugging and performance · 1/6
Debug with a method: reproduce, read the error, guess, check with a tool, fix, and add a test.
Prefer a video by a teacher? Find free videos on “android studio debugger breakpoints layout inspector compose recomposition profiler” on YouTube ↗
In real life: A laggy order history screen
Users of a food app complained that the order history stuttered. Layout Inspector showed each row recomposing on every scroll frame, because each row formatted dates and prices inside the composable from a shared state object. The developer moved formatting into the ViewModel, added keys to the LazyColumn, and checked on a release build on a budget phone: scrolling became smooth.
// Before: formatting inside the row on every recomposition
// Text(SimpleDateFormat("dd MMM yyyy").format(Date(order.time)))
// After: formatted once in the ViewModel's UiState
data class OrderRowUi(val id: Long, val dateText: String, val amountText: String)
// LazyColumn { items(rows, key = { it.id }) { OrderRow(it) } }Practice (0/3 done)
Your Compose screen feels slow in a debug build. What should you do first?
Which tool shows how many times each composable recomposed?
Take a list screen from your app. (1) Set a conditional breakpoint that pauses only for one specific item id and inspect its values. (2) Open Layout Inspector and note the recomposition counts while scrolling. (3) Fix one cause of extra work (keys, moving formatting to the ViewModel, or remember). (4) Compare scrolling in debug and release builds.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Unit tests with JUnit and coroutinesTesting Android apps · same module
- Testing basics and the test pyramidTesting Android apps · same module
- Reading errors and debuggingJava Programming (Core to Spring Boot) · Control flow and methods
- PerformanceFlutter and Dart · Animations and performance
- Debugging like a pro: DevTools and VS CodeFrontend Web Development · Async JavaScript, modules and tools
- Building real projects: CMake, warnings, debuggers and sanitizersC++ Programming (modern C++ and DSA) · Exceptions, concurrency and building projects with CMake
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What does a breakpoint do?
Answer: Pauses execution at a line so you can inspect values
Run in Debug mode to use it.
Which is a common cause of janky Compose screens?
Answer: Heavy work like sorting or formatting inside composable bodies
Move work to the ViewModel or remember it.
What are Baseline Profiles for?
Answer: Improving start-up and early frame performance through ahead-of-time compilation of key paths
They ship hints to compile hot code early.
Which should you never log?
Answer: Passwords and OTPs
Logs must not contain secrets or personal data.
Which function shows Compose content in an activity?Related
What does "Step Into" do in a debugger?Related
Answer: Goes inside the method called on the current line
Step Into enters the called method.
What is recomposition?Related
Answer: Compose re-running composables that read changed state
Only affected composables re-run.
Why is debug mode not good for judging speed?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- This is the last topic of “Testing Android apps”. The module exam comes next.
- Module 10 exam: Testing Android apps · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Publishing on the Play Store and Firebase. 50 topics left in the course before the final exam.