Skip to content
Android App Crashes: Causes, Detection, and Fixes

9 Minutes

Android App Crashes: Causes, Detection, and Fixes

Fix Bugs Faster! Log Collection Made Easy

Get started

Android app crashes will cost us users and damage our Play Store ranking. To prevent them from happening, we need to understand the most frequent causes of crashes, read the stack trace effectively, and have plans for common painpoints such as null values.

This article will give you the tools to do that. When you get to the bottom, you’ll know how to:

  • Find the root causes from a stack trace fast.
  • Deploy concrete, battle-tested fixes for NullPointerException, memory errors, network failures, and more.
  • Monitor crashes in production before users report them.
  • Reproduce crashes locally without needing the user’s device.

What an Android app crash is

An Android app crashes when the system encounters an unhandled exception or signal and has no recovery path. The OS terminates the process immediately and shows the user an “app has stopped” dialog.

Note that crashes can happen in the foreground or background. A broadcast receiver or background service can trigger a crash, even when the user isn’t actively using your app. This makes them harder to reproduce, and easier to miss.

Most common causes of Android app crashes

Most Android crashes trace back to a small set of root causes. These can be broken down into application errors, resource and memory issues, unhandled background exceptions, network or API failures, and OS or dependency compatibility problems.

The table below maps each major cause to a real-world example, so you can recognize them faster in your own stack traces.

CauseExample
NullPointerExceptionCalling .length() on a String returned by an API that started returning null after a backend change
OutOfMemoryErrorLoading a full-resolution camera bitmap into an ImageView without downsampling
Unhandled exception in background threadA coroutine making a database write throws an SQLiteException with no CoroutineExceptionHandler
Network or API failureAn API call made without a timeout hangs indefinitely, then throws SocketTimeoutException with no catch block
OS or dependency compatibilityA third-party SDK calls a method deprecated in Android 12 that throws IllegalStateException on newer devices

You can avoid a large number of problems simply by managing memory deliberately, handling unexpected states explicitly and handling exceptions at the right boundaries.

How to read an Android crash stack trace

A stack trace is the most important diagnostic artifact you’ll get from a crash. Think of it like a trail of breadcrumbs: it shows you where the failure occurred and the sequence of calls that led to it.

Every Java or Kotlin crash gives you two critical pieces of information:

  • Exception type (line 1). This identifies the category of failure and points directly to the root cause.
  • Throw location (line 2). This shows the class, method, file, and line number where the exception was thrown.

Below those two lines, each stack frame shows the call chain that led to the crash. Walk down from the top until you find a class from your own codebase. That’s where you’ll need to apply the fix.

💡 Important: you can print a stack trace at any point in your code using Thread.dumpStack() and other simple methods.
Android Developer Docs

Java and Kotlin stack traces

java.lang.NullPointerException: crash sample
  at com.example.app.MainActivity.onClick(MainActivity.java:27)
  at android.view.View.performClick(View.java:6134)

Line 1 tells you the exception type (NullPointerException) and line 2 points to MainActivity.java at line 27. That’s exactly where to start debugging.

Native (C and C++) stack traces

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
  #00 pc 0000000000042f89 /data/app/com.example.app/lib/arm64/libexample.so
  #01 pc 0000000000000640 /data/app/com.example.app/lib/arm64/libexample.so

Look for the signal number (SIGSEGV, SIGABRT), the fault address, and the backtrace frames. If function names appear as raw addresses instead of readable symbols, upload a native debug symbols file to Google Play Console to deobfuscate them.

How to reproduce Android crashes locally

To debug Android crashes locally, you need to be able to reproduce them effectively. This means simulating the conditions that your app is going to encounter out in the world, notably low memory and network failures.

Simulating low memory

  1. Open AVD Manager in Android Studio.
  2. Create a new virtual device and set the RAM to match the lower end of your target device range.
  3. Run your heaviest user flows on that AVD and monitor heap usage in Android Studio Profiler.

This reliably surfaces OutOfMemoryError crashes that only appear on entry-level devices.

Simulating network failures

  1. Enable airplane mode on a physical device or emulator while an active API call is in progress.
  2. Observe whether the app crashes or surfaces a recoverable error state.
  3. For more granular control, start your emulator with network degradation flags:
emulator -avd [your-avd-image] -netdelay 20000 -netspeed gsm

This sets a 20-second delay and GSM-speed throughput, which surfaces crashes that only appear under degraded connections.

How to fix Android app crashes

There’s no single magic formula for fixing Android crashes. Instead, it’s about adopting a series of good practices that anticipate potential problems, handle unexpected conditions explicitly, and prevent errors from propagating until they crash the app.

Handle null safely in Kotlin and Java

In Kotlin, be sure to declare variables as nullable only when null is a valid state. You can use the safe call operator (?.) to avoid explicit null checks on every access, and the Elvis operator (?:) to define a fallback:

val length: Int = string?.length ?: 0

Avoid the !! operator. It tells the compiler to treat a nullable value as non-null and throws an NPE (NullPointerException) at runtime if it isn’t. In Java, annotate parameters and return types with @Nullable and @NonNull so the IDE surfaces warnings at compile time wherever a nullable reference is used without a guard.

Manage memory and prevent leaks

  1. Add LeakCanary to your debug dependencies. It automatically detects retained objects after their expected lifecycle ends and shows the reference chain holding them.
  2. Open Android Studio Profiler during your main user flows and watch for heap usage that grows without returning to baseline.
  3. Replace manual Bitmap loading with Glide or Coil, which handle downsampling, caching, and lifecycle awareness automatically.
  4. Close database connections, file handles, and cursors explicitly in finally blocks or use Kotlin’s use extension.
  5. Avoid holding a reference to an Activity or View in a singleton. Use the application context when you need a context outside a lifecycle-aware component.

Catch unhandled exceptions in background threads

Wrap coroutine launches with a CoroutineExceptionHandler to intercept uncaught exceptions without crashing the process:

val handler = CoroutineExceptionHandler { _, exception ->
    Log.e("Coroutine", "Caught: $exception")
}
CoroutineScope(Dispatchers.IO + handler).launch {
    // your work here
}

For operations on raw threads, implement Thread.UncaughtExceptionHandler and log or report the exception before the process terminates. Catching at the thread level lets you fail gracefully and keep the rest of the app running.

Handle network failures gracefully

  1. Check for connectivity before making requests using ConnectivityManager.
  2. Set explicit timeouts on your HTTP client so a hanging request never blocks the thread indefinitely.
  3. Implement retry logic with exponential backoff for transient failures.
  4. Parse API responses defensively: never assume a field is non-null, even if it was previously required.
  5. Return a meaningful error state to the UI rather than letting the exception propagate uncaught.

Test across OS versions and devices

Android’s open-source model and diverse array of hardware manufacturers means developers must plan for significant platform fragmentation, using emulators, testing tools and physical devices.

Use emulators to cover your minimum and maximum supported API levels, then use Firebase Test Lab or a physical device matrix to catch device-specific behavior that the emulators miss.

It’s also worth subscribing to Android release notes before each major OS update, and audit your dependency list for deprecated API usage.

How to monitor crashes in production

No developer can anticipate or reproduce every condition that real users will encounter. Production crash monitoring shows which failures are actually affecting users, how frequently they occur, and which devices, Android versions, app versions, or code paths trigger them.

Android vitals in Play Console

Google Play Android vitals page showing app quality monitoring and debugging information for crashes, ANRs, and other user-impacting issues.

Android vitals tracks your crash rate automatically once your app is published. Key metrics are the user-perceived crash rate (the percentage of daily active users who experience a crash) and the user-perceived ANR rate (the percentage of daily active users who experience at least one ‘Application Not Responding’ error).

At the time of publishing (August 2026), Google defines these metrics as follows:

  • User-perceived crash rate: 1.09%.
  • User-perceived ANR rate: 0.47%.

Exceeding a bad-behavior threshold may reduce an app’s visibility on Google Play and may trigger a warning on its store listing.

You can find the latest thresholds on the Android vitals page and get more information in the Play Console documentation. Note that Play Console will send alerts when your crash rate spikes, so you don’t have to monitor it manually.

Remote crash reporting tools

Bugfender homepage showing its app logging and bug monitoring platform for collecting logs, errors, and crashes remotely from user devices.

Android vitals shows you that crashes are happening. It doesn’t always show you why, especially when crashes happen in the background or are caused by edge-case devices you don’t own.

This is where remote logging can really help. And at this point it feels helpful to mention the logger we’ve developed ourselves.

Bugfender captures device logs continuously and sends them to a dashboard you can inspect without needing physical access to the device. When a crash occurs, you get the full log context leading up to it, not just the stack trace.

Try Bugfender free and start capturing logs in minutes.

FAQs about Android App Crashes

What is the most common cause of Android app crashes?

NullPointerException is a frequently reported crash type on Google Play. It occurs when code tries to access a method or property on a null object reference. Kotlin’s type system reduces NPE frequency significantly compared to Java by making nullability explicit at compile time, which catches a large category of null bugs before they reach production.

What is the difference between a crash and an ANR?

A crash terminates the app process immediately due to an unhandled exception or signal. An ANR (Application Not Responding) occurs when the main thread is blocked for more than 5 seconds without responding to user input. ANRs don’t always terminate the app but produce a system dialog that lets the user force-stop it.

How do I see crash logs on a device?

Connect the device to Android Studio and open Logcat. Filter by “crash” or your app’s package name to isolate the relevant output. For production crashes on devices you don’t have physical access to, you need Android vitals or a remote crash reporting tool to retrieve logs.

Does Kotlin reduce NullPointerException crashes?

Yes. Kotlin’s type system distinguishes nullable and non-nullable types at compile time, which catches a large category of null-related bugs before they reach production. The Google Home team reported a measurable reduction in NPE crashes during the period when they migrated new feature development to Kotlin (Android Developers).

Expect The Unexpected!

Debug Faster With Bugfender

Start for Free
blog author

Aleix Ventayol

Aleix Ventayol is CEO and co-founder of Bugfender, with 20 years' experience building apps and solutions for clients like AVG, Qustodio, Primavera Sound and Levi's. As a former CTO and full-stack developer, Aleix is passionate about building tools that solve the real problems of app development and help teams build better software.

Join thousands of developers
and start fixing bugs faster than ever.