Profiling & Performance

Tests confirm RecipeBox behaves correctly. The Android Studio Profiler answers a different question — is it behaving efficiently? A recipe list that scrolls correctly but stutters at 15 frames per second is still a bug users will notice.

The Profiler Tabs

TabShows
CPUMethod call timing and thread activity — which method is eating time on which thread
MemoryHeap allocations over time — object counts, garbage collection events, potential leaks
NetworkEvery request RecipeBox makes (e.g., fetching a recipe via Retrofit), timing and payload size
EnergyEstimated battery impact of CPU, network, and location usage
Open it via View > Tool Windows > Profiler while running RecipeBox on a device or emulator — recordings happen live, against the real running app.

Worked Example: A Janky RecyclerView Scroll

Say RecipeBox's recipe list stutters while scrolling. Recording a CPU profile session during the scroll and inspecting the frame timeline shows which frames took too long, and the call chart shows what ran during them.

// RecipeAdapter.java — the culprit
@Override
public void onBindViewHolder(RecipeViewHolder holder, int position) {
    Recipe recipe = recipes.get(position);
    Bitmap fullSizePhoto = BitmapFactory.decodeFile(recipe.photoUri); // decodes a huge file, every bind, on the main thread
    holder.imageView.setImageBitmap(fullSizePhoto);
    holder.titleView.setText(recipe.title);
}
Explanation: The CPU profile would show BitmapFactory.decodeFile consuming most of the frame's time, running directly on the main thread inside onBindViewHolder — exactly the kind of expensive, repeated work that causes dropped frames while scrolling.
// Fixed: let an image-loading library handle decoding, caching, and sizing off the main thread
@Override
public void onBindViewHolder(RecipeViewHolder holder, int position) {
    Recipe recipe = recipes.get(position);
    Glide.with(holder.itemView.getContext())
        .load(recipe.photoUri)
        .override(200, 200) // decode at thumbnail size, not full resolution
        .into(holder.imageView);
    holder.titleView.setText(recipe.title);
}
Explanation: Decoding happens off the main thread and results are cached, and .override(200, 200) avoids decoding a multi-megapixel photo just to display it at thumbnail size — re-profiling the same scroll afterward should show the CPU timeline mostly idle during frames again.

Systrace / Perfetto

For a system-wide view spanning the app, the Android framework, and the kernel scheduler at once — useful when a slowdown might not even be RecipeBox's own code — Android Studio can capture a system trace, viewable in Perfetto (the modern successor to the older systrace tool). This lesson only needs the awareness that this deeper level of tracing exists for cases the CPU Profiler's call chart doesn't fully explain.

Common Performance Mistakes

Work on the main thread. Any file I/O, database query, JSON parsing, or bitmap decode blocking the main thread risks dropped frames or an ANR (Application Not Responding) — move it to a background thread, as covered in Threads, Handlers, Executors.

Overdraw. Stacking multiple opaque backgrounds on top of each other (a themed window background, then a Fragment background, then a card background) makes the GPU paint the same pixel repeatedly — Android Studio's Debug GPU Overdraw developer option visualizes this in color.

Oversized bitmaps. Loading a recipe photo at its full camera resolution into a small thumbnail ImageView wastes both decode time and memory — always decode or request an image at roughly the size it will actually be displayed.

A fast RecyclerView doesn't help if the app is quietly leaking memory in the background. The next lesson, Leaks & StrictMode, covers catching exactly that kind of problem before it ships.