SHAKIL.DEV

SHAKIL.DEV

Debug Your Android App: Logcat, Breakpoints and Crashes
โ† BACK TO TRANSMISSIONS
October 21, 2026

Debug Your Android App: Logcat, Breakpoints and Crashes

Crashes are just clues. Learn to use Logcat, read stack traces, fix common beginner crashes and pause your app with breakpoints in Android Studio.

Your app crashed? Congratulations, you are now a real Android developer! ๐Ÿ˜„ Every developer, from beginners to Google engineers, writes bugs every single day. The difference is that experienced developers know how to debug an Android app quickly. In Part 16: Save Settings with DataStore, we saved user settings. In this part, you will learn the tools that find and fix problems: Logcat, stack traces, breakpoints and a few Compose tools. After this lesson, a crash will not scare you anymore. It will just be a clue.

Bugs Are Normal (Really)

Think of a bug like a flat tyre on a rickshaw. It is annoying, but it happens to everyone. A good rickshaw driver does not cry. He checks the tyre, finds the hole and fixes it.

Debugging works the same way:

  1. See the problem (the app crashes or shows the wrong thing).
  2. Find where it happens (Logcat and the stack trace).
  3. Understand why it happens (breakpoints and variables).
  4. Fix it and test again.

Let's learn the tools for each step.

Step 1: Open the Logcat Window

Logcat is a live diary of everything happening on your phone or emulator. Android, other apps and your app all write messages into it.

To open it:

  1. Run your app on an emulator or phone (the green Run โ–ถ button).
  2. Go to View โ†’ Tool Windows โ†’ Logcat. You can also click the Logcat tab at the bottom of Android Studio.

You will see a lot of messages flying by. Most of them are not from your app. So we need to filter.

Filter Logcat with Queries

At the top of the Logcat window there is a search box. Modern Android Studio uses a simple query language there. Try these:

package:mine

This shows only logs from your project's app. This is the most useful filter. Use it almost always.

package:mine level:error

This shows only errors (and anything more serious) from your app. Perfect for finding crashes.

package:mine tag:FruitApp

This shows only messages with the tag FruitApp (we will write these next).

is:crash

This shows only crashes.

The log levels, from least to most serious, are: VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT. When you write level:warn, you see WARN and everything above it.

Tip: Press Ctrl + Space inside the Logcat search box. Android Studio will suggest keys like package:, tag:, level: and message: for you.

Step 2: Write Your Own Log Messages

You can write your own messages into Logcat. It is like leaving notes for yourself: "I was here, and this value was 5."

import android.util.Log

private const val TAG = "FruitApp"

fun loadFruits() {
    Log.d(TAG, "loadFruits() started")

    val fruits = listOf("Mango", "Banana", "Jackfruit")
    Log.d(TAG, "We have ${fruits.size} fruits")

    if (fruits.isEmpty()) {
        Log.e(TAG, "Fruit list is empty! Something is wrong.")
    }
}

What this means:

  • TAG is a short label. It helps you find your messages with tag:FruitApp.
  • Log.d(...) writes a debug message. Use it for normal "what is happening" notes.
  • Log.e(...) writes an error message. It shows in red.
  • There are also Log.i (info), Log.w (warning) and Log.v (verbose).

You can even log an exception:

try {
    val response = api.getFruits()
} catch (e: Exception) {
    Log.e(TAG, "Network call failed", e)
}

Passing e as the third value prints the full error details in Logcat.

Warning: Never log passwords, tokens or private user data. Logcat can be read during development, and you don't want secrets there.

Step 3: Read a Crash Stack Trace

When your app crashes, Logcat shows a big red block of text. This is the stack trace. It looks scary, but you only need to read a few lines. Here is an example:

FATAL EXCEPTION: main
Process: com.example.myfirstapp, PID: 12345
java.lang.IndexOutOfBoundsException: Index 3 out of bounds for length 3
    at java.util.ArrayList.get(ArrayList.java:437)
    at com.example.myfirstapp.FruitScreenKt.FruitDetail(FruitScreen.kt:42)
    at com.example.myfirstapp.MainActivity$onCreate$1.invoke(MainActivity.kt:25)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(...)
    ...

How to read it, like a detective ๐Ÿ•ต๏ธ:

  1. The first red line tells you what went wrong: IndexOutOfBoundsException: Index 3 out of bounds for length 3. You asked for item number 3, but the list only has items 0, 1 and 2.
  2. Find the first line with your package name (com.example.myfirstapp). Here it is FruitScreen.kt:42. That means file FruitScreen.kt, line 42.
  3. Click the blue link (FruitScreen.kt:42). Android Studio jumps straight to that line.

Ignore the lines from java.util, android. and androidx. at first. Those are library code. The bug is almost always in your code.

Look for "Caused by:"

Sometimes the stack trace has a second part that starts with Caused by:.

java.lang.RuntimeException: Unable to start activity ...
    ...
Caused by: java.lang.NullPointerException
    at com.example.myfirstapp.MainActivity.onCreate(MainActivity.kt:18)

The last Caused by: is usually the real reason. The top error is just the "outside wrapper". Scroll down and read the last Caused by: first.

Common Beginner Crashes (and How to Fix Them)

Here are the crashes you will probably meet first.

1. NullPointerException and !!

val name: String? = null
val length = name!!.length   // ๐Ÿ’ฅ crash

The !! operator means "I promise this is not null." If it is null, the app crashes.

Fix: Use safe calls instead of !!.

val length = name?.length ?: 0

?. means "only if not null", and ?: 0 gives a default value.

2. NetworkOnMainThreadException

You called the internet directly on the main thread (the UI thread). Android does not allow this, because the screen would freeze.

Fix: Do network work inside a coroutine, like we did with Retrofit in Part 13. Use viewModelScope.launch { ... } and make your Retrofit function a suspend function.

3. Missing INTERNET Permission

You see errors like SecurityException: Permission denied (missing INTERNET permission?) or UnknownHostException.

Fix: Add this line to AndroidManifest.xml, above the <application> tag:

<uses-permission android:name="android.permission.INTERNET" />

Tip: UnknownHostException can also mean the emulator has no internet, or the URL has a typo. Open Chrome on the emulator and check if any website loads.

4. IndexOutOfBoundsException

You asked for an item that does not exist in a list (like our example above).

Fix: Check the size first, or use getOrNull:

val fruit = fruits.getOrNull(index)
if (fruit != null) {
    Text(fruit)
}

5. ClassCastException

You told Kotlin "this thing is a String", but it was really an Int.

val value: Any = 42
val text = value as String   // ๐Ÿ’ฅ crash

Fix: Use the safe cast as?, which gives null instead of crashing:

val text = value as? String ?: "Not a string"

6. Data Lost When You Rotate the Phone

This one is not always a crash, but it feels like one. You type something, rotate the phone, and it disappears. Or the app crashes because a value became empty.

Why: When you rotate, Android rebuilds the Activity. Normal remember values are lost.

Fix: Use rememberSaveable for small UI values, and keep important data in a ViewModel (Part 9), which survives rotation.

var text by rememberSaveable { mutableStateOf("") }

Step 4: Use Breakpoints and the Debugger

Logs are great, but sometimes you want to pause the app and look inside. That is what a breakpoint does. It is like pressing "pause" on a movie to look at every detail of one scene.

Set a breakpoint

  1. Open a Kotlin file, for example your ViewModel.
  2. Click in the gutter (the empty space just left of the line numbers) next to a line. A red dot appears. That is your breakpoint.

Run in debug mode

  1. Click the Debug button (the green bug icon ๐Ÿž next to Run), or go to Run โ†’ Debug 'app'.
  2. Use the app until it reaches your line. The app pauses, and the Debug window opens at the bottom.

Move step by step

In the Debug window, you will find these buttons:

  • Step Over (F8): Run this line and go to the next line.
  • Step Into (F7): Go inside the function on this line.
  • Step Out (Shift + F8): Finish this function and go back to the caller.
  • Resume Program (F9): Continue running until the next breakpoint.

Inspect variables

While paused, look at the Variables panel. You can see the value of every variable right now. For example, you may see fruits = size 0 and suddenly understand why your list is empty!

Evaluate Expression

Press Alt + F8 (or right-click โ†’ Evaluate Expression). You can type any Kotlin code, like fruits.size or fruits.first().name, and see the answer immediately. It is like asking your app a question while it is frozen.

Tip: Right-click a red dot to add a condition, like index == 3. The app will pause only when that is true. Very useful inside loops.

Step 5: Compose-Specific Tools

Jetpack Compose has some extra helpers.

@Preview for quick checks

You already used @Preview in earlier parts. Use it to check a single composable with fake data, without running the whole app.

@Preview(showBackground = true)
@Composable
fun FruitCardPreview() {
    MyFirstAppTheme {
        FruitCard(name = "Mango")
    }
}

If something looks wrong in the preview, the bug is in that composable, not in your data.

Layout Inspector

When the app is running, go to View โ†’ Tool Windows โ†’ Layout Inspector (in newer versions it may open inside the Running Devices window). It shows your screen as a tree of composables. Click any part of the screen and see its size, padding and parameters. Great for "Why is my button invisible?" problems.

Recomposition counts

The Layout Inspector can also show recomposition counts: how many times each composable was redrawn. If a small composable recomposes hundreds of times, it may be slowing your app. As a beginner, just know this exists. You will use it later for performance work.

Let AI Help (But Understand the Fix)

Android Studio has a built-in AI assistant called Gemini in Android Studio. It can work with Logcat and App Quality Insights to explain crashes. When you see a crash in Logcat, look for the Gemini option next to it and ask it to explain.

AI assistants (Gemini, ChatGPT, Claude and others) can be very helpful. But please remember one rule: you must understand the fix before you use it. If you paste code you don't understand, you will meet the same bug again tomorrow, and you won't know why. Ask the AI "why?" until it makes sense.

Tip: App Quality Insights (View โ†’ Tool Windows โ†’ App Quality Insights) shows crash reports from real users after you publish your app on Google Play. We will publish in the next part!

How to Ask for Help (Checklist)

Sometimes you are stuck for hours. That is okay. Asking for help is a skill. Before you post on Stack Overflow, a Facebook group or Discord, check this list:

  • โœ… Search first. Copy the first error line (like NetworkOnMainThreadException) into Google. Someone has probably had it before.
  • โœ… Include the stack trace as text, not a blurry phone photo.
  • โœ… Show minimal code. Only the function that crashes, not your whole project.
  • โœ… Say what you expected and what happened instead.
  • โœ… Say what you already tried.
  • โœ… Mention versions if relevant (Android Studio version, library versions).

A good question often gets an answer in minutes. And many times, while writing the question clearly, you find the answer yourself! ๐Ÿ˜Š

Try It Yourself

  1. Make a crash on purpose. Add val x = listOf(1, 2)[5] inside a button click. Run the app, click the button, and find the crash in Logcat with package:mine level:error. Click the link to your file.
  2. Log your ViewModel. Add Log.d(TAG, ...) messages to your shopping list ViewModel from Part 15. Show a message every time an item is added or deleted. Filter with tag:.
  3. Use a breakpoint. Put a breakpoint inside your Retrofit loading function from Part 13. Run with Debug, then use the Variables panel to see what the API returned.

Frequently Asked Questions

My Logcat is empty. What should I do? Make sure your app is running and the correct device is selected in the dropdown at the top of the Logcat window. Also check your query: remove extra filters and try only package:mine.

What is the difference between Log.d and println? Both appear in Logcat, but Log.d has a tag and a level, so you can filter it easily. Use Log in Android apps.

The debugger does not stop at my breakpoint. Why? You may have clicked Run instead of Debug. Or that line of code never ran. Add a Log.d just before it to check whether the code is reached at all.

Quick Recap

  • Bugs are normal. Debugging is a skill you can learn.
  • Open Logcat with View โ†’ Tool Windows โ†’ Logcat and filter with package:mine level:error.
  • Write your own logs with Log.d(TAG, "...") and Log.e(TAG, "...", e).
  • In a stack trace, find the first line with your package name and read the last "Caused by:".
  • Common fixes: avoid !!, use coroutines for network, add the INTERNET permission, use getOrNull and as?, and keep state in a ViewModel or rememberSaveable.
  • Use breakpoints, Step Over/Into, the Variables panel and Evaluate Expression to look inside your app.
  • Use @Preview and Layout Inspector for Compose UI problems.
  • AI can help explain crashes, but always understand the fix yourself.

Your app is now stable and tested. It is time to share it with the world! ๐Ÿš€

Part 18: Publish Your First Android App on Google Play

Next in Android for Beginners โ†’
Publish Your First Android App on Google Play (Step by Step)